parent
dd4b0de459
commit
e31b768202
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* ARM AArch64 specific prototypes for bsd-user
|
||||
*
|
||||
* Copyright (c) 2015 Stacey D. Son <sson at FreeBSD>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _TARGET_ARCH_H_
|
||||
#define _TARGET_ARCH_H_
|
||||
|
||||
#include "qemu.h"
|
||||
|
||||
void target_cpu_set_tls(CPUARMState *env, target_ulong newtls);
|
||||
target_ulong target_cpu_get_tls(CPUARMState *env);
|
||||
|
||||
#endif /* !_TARGET_ARCH_H_ */
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* ARM AArch64 specific CPU for bsd-user
|
||||
*
|
||||
* Copyright (c) 2015 Stacey D. Son <sson@FreeBSD.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "target_arch.h"
|
||||
|
||||
/* See cpu_set_user_tls() in arm64/arm64/vm_machdep.c */
|
||||
void target_cpu_set_tls(CPUARMState *env, target_ulong newtls)
|
||||
{
|
||||
|
||||
env->cp15.tpidr_el[0] = newtls;
|
||||
}
|
||||
|
||||
target_ulong target_cpu_get_tls(CPUARMState *env)
|
||||
{
|
||||
|
||||
return (env->cp15.tpidr_el[0]);
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* ARM AArch64 cpu init and loop
|
||||
*
|
||||
* Copyright (c) 2015 Stacey D. Son <sson at Freebsd>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef _TARGET_ARCH_CPU_H_
|
||||
#define _TARGET_ARCH_CPU_H_
|
||||
|
||||
#include "target_arch.h"
|
||||
|
||||
// #define DEBUG_PRINTF(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define DEBUG_PRINTF(...)
|
||||
|
||||
#define TARGET_DEFAULT_CPU_MODEL "any"
|
||||
|
||||
#define TARGET_CPU_RESET(cpu)
|
||||
|
||||
static inline void target_cpu_init(CPUARMState *env,
|
||||
struct target_pt_regs *regs)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!(arm_feature(env, ARM_FEATURE_AARCH64))) {
|
||||
fprintf(stderr, "The selected ARM CPU does not support 64 bit mode\n");
|
||||
exit(1);
|
||||
}
|
||||
for (i = 0; i < 31; i++) {
|
||||
env->xregs[i] = regs->regs[i];
|
||||
}
|
||||
env->pc = regs->pc;
|
||||
env->xregs[31] = regs->sp;
|
||||
}
|
||||
|
||||
static inline void target_cpu_loop(CPUARMState *env)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
int trapnr;
|
||||
target_siginfo_t info;
|
||||
uint64_t code, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
|
||||
uint32_t pstate;
|
||||
abi_long ret;
|
||||
|
||||
for (;;) {
|
||||
cpu_exec_start(cs);
|
||||
trapnr = cpu_exec(cs);
|
||||
cpu_exec_end(cs);
|
||||
process_queued_cpu_work(cs);
|
||||
|
||||
switch (trapnr) {
|
||||
case EXCP_SWI:
|
||||
/* See arm/arm/trap.c cpu_fetch_syscall_args() */
|
||||
code = env->xregs[8];
|
||||
if (code == TARGET_FREEBSD_NR_syscall) {
|
||||
code = env->xregs[0];
|
||||
arg1 = env->xregs[1];
|
||||
arg2 = env->xregs[2];
|
||||
arg3 = env->xregs[3];
|
||||
arg4 = env->xregs[4];
|
||||
arg5 = env->xregs[5];
|
||||
arg6 = env->xregs[6];
|
||||
arg7 = env->xregs[7];
|
||||
arg8 = 0;
|
||||
} else if (code == TARGET_FREEBSD_NR___syscall) {
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
code = env->xregs[1];
|
||||
#else
|
||||
code = env->xregs[0];
|
||||
#endif
|
||||
arg1 = env->xregs[2];
|
||||
arg2 = env->xregs[3];
|
||||
arg3 = env->xregs[4];
|
||||
arg4 = env->xregs[5];
|
||||
arg5 = env->xregs[6];
|
||||
arg6 = env->xregs[7];
|
||||
arg7 = 0;
|
||||
arg8 = 0;
|
||||
} else {
|
||||
arg1 = env->xregs[0];
|
||||
arg2 = env->xregs[1];
|
||||
arg3 = env->xregs[2];
|
||||
arg4 = env->xregs[3];
|
||||
arg5 = env->xregs[4];
|
||||
arg6 = env->xregs[5];
|
||||
arg7 = env->xregs[6];
|
||||
arg8 = env->xregs[7];
|
||||
}
|
||||
ret = do_freebsd_syscall(env, code, arg1, arg2, arg3,
|
||||
arg4, arg5, arg6, arg7, arg8);
|
||||
/*
|
||||
* The carry bit is cleared for no error; set for error.
|
||||
* See arm64/arm64/vm_machdep.c cpu_set_syscall_retval()
|
||||
*/
|
||||
pstate = pstate_read(env);
|
||||
if (ret >= 0) {
|
||||
pstate &= ~PSTATE_C;
|
||||
env->xregs[0] = ret;
|
||||
} else if (ret == -TARGET_ERESTART) {
|
||||
env->pc -= 4;
|
||||
break;
|
||||
} else if (ret != -TARGET_EJUSTRETURN) {
|
||||
pstate |= PSTATE_C;
|
||||
env->xregs[0] = -ret;
|
||||
}
|
||||
pstate_write(env, pstate);
|
||||
break;
|
||||
|
||||
case EXCP_INTERRUPT:
|
||||
/* Just indicate that signals should be handle ASAP. */
|
||||
break;
|
||||
|
||||
case EXCP_UDEF:
|
||||
info.si_signo = TARGET_SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_ILLOPN;
|
||||
info.si_addr = env->pc;
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
break;
|
||||
|
||||
|
||||
case EXCP_PREFETCH_ABORT:
|
||||
case EXCP_DATA_ABORT:
|
||||
info.si_signo = TARGET_SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
/* XXX: check env->error_code */
|
||||
info.si_code = TARGET_SEGV_MAPERR;
|
||||
info.si_addr = env->exception.vaddress;
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
break;
|
||||
|
||||
case EXCP_DEBUG:
|
||||
case EXCP_BKPT:
|
||||
info.si_signo = TARGET_SIGTRAP;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_TRAP_BRKPT;
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
break;
|
||||
|
||||
case EXCP_ATOMIC:
|
||||
cpu_exec_step_atomic(cs);
|
||||
break;
|
||||
|
||||
case EXCP_YIELD:
|
||||
/* nothing to do here for user-mode, just resume guest code */
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
|
||||
trapnr);
|
||||
cpu_dump_state(cs, stderr, 0);
|
||||
abort();
|
||||
} /* switch() */
|
||||
process_pending_signals(env);
|
||||
/*
|
||||
* Exception return on AArch64 always clears the exclusive
|
||||
* monitor, so any return to running guest code implies this.
|
||||
* A strex (successful or otherwise) also clears the monitor, so
|
||||
* we don't need to specialcase EXCP_STREX.
|
||||
*/
|
||||
env->exclusive_addr = -1;
|
||||
} /* for (;;) */
|
||||
}
|
||||
|
||||
/* See arm64/arm64/vm_machdep.c cpu_fork() */
|
||||
static inline void target_cpu_clone_regs(CPUARMState *env, target_ulong newsp)
|
||||
{
|
||||
if (newsp)
|
||||
env->xregs[31] = newsp;
|
||||
env->regs[0] = 0;
|
||||
env->regs[1] = 0;
|
||||
pstate_write(env, 0);
|
||||
}
|
||||
|
||||
static inline void target_cpu_reset(CPUArchState *cpu)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* !_TARGET_ARCH_CPU_H */
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* ARM AArch64 ELF definitions for bsd-user
|
||||
*
|
||||
* Copyright (c) 2015 Stacey D. Son <sson at Freebsd>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef _TARGET_ARCH_ELF_H_
|
||||
#define _TARGET_ARCH_ELF_H_
|
||||
|
||||
#define ELF_START_MMAP 0x80000000
|
||||
#define ELF_ET_DYN_LOAD_ADDR 0x100000
|
||||
|
||||
#define elf_check_arch(x) ( (x) == EM_AARCH64 )
|
||||
|
||||
#define ELF_CLASS ELFCLASS64
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
#define ELF_DATA ELFDATA2MSB
|
||||
#else
|
||||
#define ELF_DATA ELFDATA2LSB
|
||||
#endif
|
||||
#define ELF_ARCH EM_AARCH64
|
||||
|
||||
#define USE_ELF_CORE_DUMP
|
||||
#define ELF_EXEC_PAGESIZE 4096
|
||||
|
||||
enum
|
||||
{
|
||||
ARM_HWCAP_A64_FP = 1 << 0,
|
||||
ARM_HWCAP_A64_ASIMD = 1 << 1,
|
||||
ARM_HWCAP_A64_EVTSTRM = 1 << 2,
|
||||
ARM_HWCAP_A64_AES = 1 << 3,
|
||||
ARM_HWCAP_A64_PMULL = 1 << 4,
|
||||
ARM_HWCAP_A64_SHA1 = 1 << 5,
|
||||
ARM_HWCAP_A64_SHA2 = 1 << 6,
|
||||
ARM_HWCAP_A64_CRC32 = 1 << 7,
|
||||
};
|
||||
|
||||
#define ELF_HWCAP (ARM_HWCAP_A64_FP | ARM_HWCAP_A64_ASIMD)
|
||||
|
||||
#endif /* _TARGET_ARCH_ELF_H_ */
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* FreeBSD arm64 register structures
|
||||
*
|
||||
* Copyright (c) 2015 Stacey Son
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 _TARGET_ARCH_REG_H_
|
||||
#define _TARGET_ARCH_REG_H_
|
||||
|
||||
/* See sys/arm64/include/reg.h */
|
||||
typedef struct target_reg {
|
||||
uint64_t x[30];
|
||||
uint64_t lr;
|
||||
uint64_t sp;
|
||||
uint64_t elr;
|
||||
uint64_t spsr;
|
||||
} target_reg_t;
|
||||
|
||||
typedef struct target_fpreg {
|
||||
__uint128_t fp_q[32];
|
||||
uint32_t fp_sr;
|
||||
uint32_t fp_cr;
|
||||
} target_fpreg_t;
|
||||
|
||||
#define tswapreg(ptr) tswapal(ptr)
|
||||
|
||||
static inline void target_copy_regs(target_reg_t *regs, CPUARMState *env)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 30; i++)
|
||||
regs->x[i] = tswapreg(env->xregs[i]);
|
||||
regs->lr = tswapreg(env->xregs[30]);
|
||||
regs->sp = tswapreg(env->xregs[31]);
|
||||
regs->elr = tswapreg(env->pc);
|
||||
regs->spsr = tswapreg(pstate_read(env));
|
||||
}
|
||||
|
||||
#undef tswapreg
|
||||
|
||||
#endif /* !_TARGET_ARCH_REG_H_ */
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* ARM AArch64 specific signal definitions for bsd-user
|
||||
*
|
||||
* Copyright (c) 2015 Stacey D. Son <sson at FreeBSD>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _TARGET_ARCH_SIGNAL_H_
|
||||
#define _TARGET_ARCH_SIGNAL_H_
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
#define TARGET_REG_X0 0
|
||||
#define TARGET_REG_X30 30
|
||||
#define TARGET_REG_X31 31
|
||||
#define TARGET_REG_LR TARGET_REG_X30
|
||||
#define TARGET_REG_SP TARGET_REG_X31
|
||||
|
||||
#define TARGET_INSN_SIZE 4 /* arm64 instruction size */
|
||||
|
||||
/* Size of the signal trampolin code. See _sigtramp(). */
|
||||
#define TARGET_SZSIGCODE ((abi_ulong)(9 * TARGET_INSN_SIZE))
|
||||
|
||||
/* compare to sys/arm64/include/_limits.h */
|
||||
#define TARGET_MINSIGSTKSZ (1024 * 4) /* min sig stack size */
|
||||
#define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) /* recommended size */
|
||||
|
||||
/* sys/sys/ucontext.h XXX maybe should be in a FreeBSD wide header */
|
||||
#define TARGET_MC_GET_CLEAR_RET 0x0001
|
||||
|
||||
/* sys/arm64/include/signal.h */
|
||||
struct target_sigcontext {
|
||||
int32_t _dummy;
|
||||
};
|
||||
|
||||
/* struct __mcontext in sys/arm64/include/ucontext.h */
|
||||
|
||||
struct target_gpregs {
|
||||
uint64_t gp_x[30];
|
||||
uint64_t gp_lr;
|
||||
uint64_t gp_sp;
|
||||
uint64_t gp_elr;
|
||||
uint32_t gp_spsr;
|
||||
uint32_t gp_pad;
|
||||
};
|
||||
|
||||
struct target_fpregs {
|
||||
__uint128_t fp_q[32];
|
||||
uint32_t fp_sr;
|
||||
uint32_t fp_cr;
|
||||
uint32_t fp_flags;
|
||||
uint32_t fp_pad;
|
||||
};
|
||||
|
||||
struct target__mcontext {
|
||||
struct target_gpregs mc_gpregs;
|
||||
struct target_fpregs mc_fpregs;
|
||||
uint32_t mc_flags;
|
||||
#define TARGET_MC_FP_VALID 0x1
|
||||
uint32_t mc_pad;
|
||||
uint64_t mc_spare[8];
|
||||
};
|
||||
|
||||
typedef struct target__mcontext target_mcontext_t;
|
||||
|
||||
typedef struct target_ucontext {
|
||||
target_sigset_t uc_sigmask;
|
||||
target_mcontext_t uc_mcontext;
|
||||
abi_ulong uc_link;
|
||||
target_stack_t uc_stack;
|
||||
int32_t uc_flags;
|
||||
int32_t __spare__[4];
|
||||
} target_ucontext_t;
|
||||
|
||||
struct target_sigframe {
|
||||
target_siginfo_t sf_si; /* saved siginfo */
|
||||
target_ucontext_t sf_uc; /* saved ucontext */
|
||||
};
|
||||
|
||||
|
||||
/* compare to struct trapframe in sys/arm64/include/frame.h */
|
||||
struct target_trapframe {
|
||||
uint64_t tf_sp;
|
||||
uint64_t tf_lr;
|
||||
uint64_t tf_elr;
|
||||
uint64_t tf_spsr;
|
||||
uint64_t tf_x[30];
|
||||
};
|
||||
|
||||
/*
|
||||
* Compare to sendsig() in sys/arm64/arm64/machdep.c
|
||||
* Assumes that target stack frame memory is locked.
|
||||
*/
|
||||
static inline abi_long
|
||||
set_sigtramp_args(CPUARMState *regs, int sig, struct target_sigframe *frame,
|
||||
abi_ulong frame_addr, struct target_sigaction *ka)
|
||||
{
|
||||
/*
|
||||
* Arguments to signal handler:
|
||||
* x0 = signal number
|
||||
* x1 = siginfo pointer
|
||||
* x2 = ucontext pointer
|
||||
* pc/elr = signal handler pointer
|
||||
* sp = sigframe struct pointer
|
||||
* lr = sigtramp at base of user stack
|
||||
*/
|
||||
|
||||
regs->xregs[0] = sig;
|
||||
regs->xregs[1] = frame_addr +
|
||||
offsetof(struct target_sigframe, sf_si);
|
||||
regs->xregs[2] = frame_addr +
|
||||
offsetof(struct target_sigframe, sf_uc);
|
||||
|
||||
regs->pc = ka->_sa_handler;
|
||||
regs->xregs[TARGET_REG_SP] = frame_addr;
|
||||
regs->xregs[TARGET_REG_LR] = TARGET_PS_STRINGS - TARGET_SZSIGCODE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare to get_mcontext() in arm64/arm64/machdep.c
|
||||
* Assumes that the memory is locked if mcp points to user memory.
|
||||
*/
|
||||
static inline abi_long get_mcontext(CPUARMState *regs, target_mcontext_t *mcp,
|
||||
int flags)
|
||||
{
|
||||
int err = 0, i;
|
||||
uint64_t *gr = mcp->mc_gpregs.gp_x;
|
||||
|
||||
mcp->mc_gpregs.gp_spsr = pstate_read(regs);
|
||||
if (flags & TARGET_MC_GET_CLEAR_RET) {
|
||||
gr[0] = 0UL;
|
||||
mcp->mc_gpregs.gp_spsr &= ~CPSR_C;
|
||||
} else {
|
||||
gr[0] = tswap64(regs->xregs[0]);
|
||||
}
|
||||
|
||||
for (i = 1; i < 30; i++)
|
||||
gr[i] = tswap64(regs->xregs[i]);
|
||||
|
||||
mcp->mc_gpregs.gp_sp = tswap64(regs->xregs[TARGET_REG_SP]);
|
||||
mcp->mc_gpregs.gp_lr = tswap64(regs->xregs[TARGET_REG_LR]);
|
||||
mcp->mc_gpregs.gp_elr = tswap64(regs->pc);
|
||||
|
||||
/* XXX FP? */
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Compare to set_mcontext() in arm64/arm64/machdep.c */
|
||||
static inline abi_long set_mcontext(CPUARMState *regs, target_mcontext_t *mcp,
|
||||
int srflag)
|
||||
{
|
||||
int err = 0, i;
|
||||
const uint64_t *gr = mcp->mc_gpregs.gp_x;
|
||||
|
||||
for (i = 0; i < 30; i++)
|
||||
regs->xregs[i] = tswap64(gr[i]);
|
||||
|
||||
regs->xregs[TARGET_REG_SP] = tswap64(mcp->mc_gpregs.gp_sp);
|
||||
regs->xregs[TARGET_REG_LR] = tswap64(mcp->mc_gpregs.gp_lr);
|
||||
regs->pc = mcp->mc_gpregs.gp_elr;
|
||||
pstate_write(regs, mcp->mc_gpregs.gp_spsr);
|
||||
|
||||
/* XXX FP? */
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Compare to sys_sigreturn() in arm64/arm64/machdep.c */
|
||||
static inline abi_long get_ucontext_sigreturn(CPUARMState *regs,
|
||||
abi_ulong target_sf, abi_ulong *target_uc)
|
||||
{
|
||||
uint32_t pstate = pstate_read(regs);
|
||||
|
||||
*target_uc = 0;
|
||||
|
||||
if ((pstate & PSTATE_M) != PSTATE_MODE_EL0t ||
|
||||
(pstate & (PSTATE_F | PSTATE_I | PSTATE_A | PSTATE_D)) != 0) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
|
||||
*target_uc = target_sf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif /* !_TARGET_ARCH_SIGNAL_H_ */
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* ARM AArch64 sigcode for bsd-user
|
||||
*
|
||||
* Copyright (c) 2015 Stacey D. Son <sson at FreeBSD>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef _TARGET_ARCH_SIGTRAMP_H_
|
||||
#define _TARGET_ARCH_SIGTRAMP_H_
|
||||
|
||||
/* Compare to ENTRY(sigcode) in arm64/arm64/locore.S */
|
||||
static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
|
||||
unsigned sys_sigreturn)
|
||||
{
|
||||
int i;
|
||||
uint32_t sys_exit = TARGET_FREEBSD_NR_exit;
|
||||
|
||||
uint32_t sigtramp_code[] = {
|
||||
/* 1 */ 0x910003e0, /* mov x0, sp */
|
||||
/* 2 */ 0x91000000 + (sigf_uc << 10), /* add x0, x0, #SIGF_UC */
|
||||
/* 3 */ 0xd2800000 + (sys_sigreturn << 5) + 0x8, /* mov x8, #SYS_sigreturn */
|
||||
/* 4 */ 0xd4000001, /* svc #0 */
|
||||
/* 5 */ 0xd2800028 + (sys_exit << 5) + 0x8, /* mov x8, #SYS_exit */
|
||||
/* 6 */ 0xd4000001, /* svc #0 */
|
||||
/* 7 */ 0x17fffffc, /* b -4 */
|
||||
/* 8 */ sys_sigreturn,
|
||||
/* 9 */ sys_exit
|
||||
};
|
||||
|
||||
for (i = 0; i < 9; i++) {
|
||||
tswap32s(&sigtramp_code[i]);
|
||||
}
|
||||
|
||||
return memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE);
|
||||
}
|
||||
#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* ARM AArch64 sysarch() system call emulation for bsd-user.
|
||||
*
|
||||
* Copyright (c) 2015 <sson at FreeBSD>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __ARCH_SYSARCH_H_
|
||||
#define __ARCH_SYSARCH_H_
|
||||
|
||||
#include "target_syscall.h"
|
||||
#include "target_arch.h"
|
||||
|
||||
/* See sysarch() in sys/arm64/arm64/sys_machdep.c */
|
||||
static inline abi_long do_freebsd_arch_sysarch(CPUARMState *env, int op,
|
||||
abi_ulong parms)
|
||||
{
|
||||
int ret = -TARGET_EOPNOTSUPP;
|
||||
|
||||
fprintf(stderr, "sysarch");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void do_freebsd_arch_print_sysarch(
|
||||
const struct syscallname *name, abi_long arg1, abi_long arg2,
|
||||
abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
|
||||
{
|
||||
|
||||
#if 0
|
||||
switch (arg1) {
|
||||
case TARGET_FREEBSD_ARM_SYNC_ICACHE:
|
||||
gemu_log("%s(ARM_SYNC_ICACHE, ...)", name->name);
|
||||
break;
|
||||
|
||||
case TARGET_FREEBSD_ARM_DRAIN_WRITEBUF:
|
||||
gemu_log("%s(ARM_DRAIN_WRITEBUF, ...)", name->name);
|
||||
break;
|
||||
|
||||
case TARGET_FREEBSD_ARM_SET_TP:
|
||||
gemu_log("%s(ARM_SET_TP, 0x" TARGET_ABI_FMT_lx ")", name->name, arg2);
|
||||
break;
|
||||
|
||||
case TARGET_FREEBSD_ARM_GET_TP:
|
||||
gemu_log("%s(ARM_GET_TP, 0x" TARGET_ABI_FMT_lx ")", name->name, arg2);
|
||||
break;
|
||||
|
||||
default:
|
||||
gemu_log("UNKNOWN OP: %d, " TARGET_ABI_FMT_lx ")", (int)arg1, arg2);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /*!__ARCH_SYSARCH_H_ */
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* ARM AArch64 thread support for bsd-user.
|
||||
*
|
||||
* Copyright (c) 2015 Stacey D. Son <sson at FreeBSD>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef _TARGET_ARCH_THREAD_H_
|
||||
#define _TARGET_ARCH_THREAD_H_
|
||||
|
||||
/* Compare to arm64/arm64/vm_machdep.c cpu_set_upcall_kse() */
|
||||
static inline void target_thread_set_upcall(CPUARMState *regs, abi_ulong entry,
|
||||
abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
|
||||
{
|
||||
abi_ulong sp;
|
||||
|
||||
/*
|
||||
* Make sure the stack is properly aligned.
|
||||
* arm64/include/param.h (STACKLIGN() macro)
|
||||
*/
|
||||
sp = (abi_ulong)((stack_base + stack_size) -
|
||||
sizeof(struct target_trapframe)) & ~(16 - 1);
|
||||
|
||||
/* sp = stack base */
|
||||
regs->xregs[31] = sp;
|
||||
/* pc = start function entry */
|
||||
regs->pc = entry & ~0x3ULL;
|
||||
/* r0 = arg */
|
||||
regs->xregs[0] = arg;
|
||||
|
||||
pstate_write(regs, PSTATE_MODE_EL0t);
|
||||
}
|
||||
|
||||
static inline void target_thread_init(struct target_pt_regs *regs,
|
||||
struct image_info *infop)
|
||||
{
|
||||
abi_long stack = infop->start_stack;
|
||||
|
||||
/*
|
||||
* Make sure the stack is properly aligned.
|
||||
* arm64/include/param.h (STACKLIGN() macro)
|
||||
*/
|
||||
|
||||
memset(regs, 0, sizeof(*regs));
|
||||
regs->regs[0] = infop->start_stack;
|
||||
regs->pc = infop->entry & ~0x3ULL;
|
||||
regs->sp = stack & ~(16 - 1);
|
||||
|
||||
#if 0
|
||||
if (bsd_type == target_freebsd) {
|
||||
regs->ARM_lr = infop->entry & 0xfffffffe;
|
||||
}
|
||||
/* FIXME - what to for failure of get_user()? */
|
||||
get_user_ual(regs->ARM_r2, stack + 8); /* envp */
|
||||
get_user_ual(regs->ARM_r1, stack + 4); /* envp */
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* !_TARGET_ARCH_THREAD_H_ */
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* ARM AArch64 VM parameters definitions for bsd-user.
|
||||
*
|
||||
* Copyright (c) 2015 Stacey D. Son <sson at FreeBSD>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef _TARGET_ARCH_VMPARAM_H_
|
||||
#define _TARGET_ARCH_VMPARAM_H_
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
/**
|
||||
* FreeBSD/arm64 Address space layout.
|
||||
*
|
||||
* ARMv8 implements up to a 48 bit virtual address space. The address space is
|
||||
* split into 2 regions at each end of the 64 bit address space, with an
|
||||
* out of range "hole" in the middle.
|
||||
*
|
||||
* We limit the size of the two spaces to 39 bits each.
|
||||
*
|
||||
* Upper region: 0xffffffffffffffff
|
||||
* 0xffffff8000000000
|
||||
*
|
||||
* Hole: 0xffffff7fffffffff
|
||||
* 0x0000008000000000
|
||||
*
|
||||
* Lower region: 0x0000007fffffffff
|
||||
* 0x0000000000000000
|
||||
*
|
||||
* The upper region for the kernel, and the lower region for userland.
|
||||
*/
|
||||
|
||||
|
||||
/* compare to sys/arm64/include/vmparam.h */
|
||||
#define TARGET_MAXTSIZ (1 * GiB) /* max text size */
|
||||
#define TARGET_DFLDSIZ (128 * MiB) /* initial data size limit */
|
||||
#define TARGET_MAXDSIZ (1 * GiB) /* max data size */
|
||||
#define TARGET_DFLSSIZ (128 * MiB) /* initial stack size limit */
|
||||
#define TARGET_MAXSSIZ (1 * GiB) /* max stack size */
|
||||
#define TARGET_SGROWSIZ (128 * KiB) /* amount to grow stack */
|
||||
|
||||
// XXX RESERVED_VA really needs to be fixed and used correctly.
|
||||
// #define TARGET_RESERVED_VA 0xf7000000
|
||||
|
||||
/* KERNBASE - 512 MB */
|
||||
#define TARGET_VM_MAXUSER_ADDRESS (0x00007fffff000000ULL - (512 * MiB))
|
||||
#define TARGET_USRSTACK TARGET_VM_MAXUSER_ADDRESS
|
||||
|
||||
static inline abi_ulong get_sp_from_cpustate(CPUARMState *state)
|
||||
{
|
||||
return state->xregs[31]; /* sp */
|
||||
}
|
||||
|
||||
static inline void set_second_rval(CPUARMState *state, abi_ulong retval2)
|
||||
{
|
||||
state->xregs[1] = retval2; /* XXX ??? */
|
||||
}
|
||||
|
||||
#endif /* ! _TARGET_ARCH_VMPARAM_H_ */
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* ARM AArch64 specific CPU for bsd-user
|
||||
*
|
||||
* Copyright (c) 2015 Stacey D. Son <sson at Freebsd>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __ARCH_SYSCALL_H_
|
||||
#define __ARCH_SYSCALL_H_
|
||||
|
||||
/*
|
||||
* The aarch64 registers are named:
|
||||
*
|
||||
* x0 through x30 - for 64-bit-wide access (same registers)
|
||||
* Register '31' is one of two registers depending on the instruction context:
|
||||
* For instructions dealing with the stack, it is the stack pointer, named rsp
|
||||
* For all other instructions, it is a "zero" register, which returns 0 when
|
||||
* read and discards data when written - named rzr (xzr, wzr)
|
||||
*
|
||||
* Usage during syscall/function call:
|
||||
* r0-r7 are used for arguments and return values
|
||||
* For syscalls, the syscall number is in r8
|
||||
* r9-r15 are for temporary values (may get trampled)
|
||||
* r16-r18 are used for intra-procedure-call and platform values (avoid)
|
||||
* The called routine is expected to preserve r19-r28
|
||||
* r29 and r30 are used as the frame register and link register (avoid)
|
||||
* See the ARM Procedure Call Reference for details.
|
||||
*/
|
||||
struct target_pt_regs {
|
||||
uint64_t regs[31];
|
||||
uint64_t sp;
|
||||
uint64_t pc;
|
||||
uint64_t pstate;
|
||||
};
|
||||
|
||||
#define ARM_SYSCALL_BASE 0 /* XXX: FreeBSD only */
|
||||
|
||||
#define TARGET_FREEBSD_ARM_SYNC_ICACHE 0
|
||||
#define TARGET_FREEBSD_ARM_DRAIN_WRITEBUF 1
|
||||
#define TARGET_FREEBSD_ARM_SET_TP 2
|
||||
#define TARGET_FREEBSD_ARM_GET_TP 3
|
||||
|
||||
#define TARGET_HW_MACHINE "arm64"
|
||||
#define TARGET_HW_MACHINE_ARCH "aarch64"
|
||||
|
||||
#endif /* !__ARCH_SYSCALL_H_ */
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* ARM 32-bit specific prototypes for bsd-user
|
||||
*
|
||||
* 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 _TARGET_ARCH_H_
|
||||
#define _TARGET_ARCH_H_
|
||||
|
||||
#include "qemu.h"
|
||||
|
||||
void target_cpu_set_tls(CPUARMState *env, target_ulong newtls);
|
||||
target_ulong target_cpu_get_tls(CPUARMState *env);
|
||||
|
||||
#endif /* !_TARGET_ARCH_H_ */
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* arm cpu related code
|
||||
*
|
||||
* 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 "target_arch.h"
|
||||
|
||||
void target_cpu_set_tls(CPUARMState *env, target_ulong newtls)
|
||||
{
|
||||
if (access_secure_reg(env)) {
|
||||
env->cp15.tpidrurw_s = newtls;
|
||||
env->cp15.tpidruro_s = newtls;
|
||||
return;
|
||||
}
|
||||
|
||||
env->cp15.tpidr_el[0] = newtls;
|
||||
env->cp15.tpidrro_el[0] = newtls;
|
||||
}
|
||||
|
||||
target_ulong target_cpu_get_tls(CPUARMState *env)
|
||||
{
|
||||
if (access_secure_reg(env))
|
||||
return (env->cp15.tpidruro_s);
|
||||
return (env->cp15.tpidrro_el[0]);
|
||||
}
|
|
@ -0,0 +1,343 @@
|
|||
/*
|
||||
* arm cpu init and loop
|
||||
*
|
||||
* Olivier Houchard
|
||||
*
|
||||
* 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 _TARGET_ARCH_CPU_H_
|
||||
#define _TARGET_ARCH_CPU_H_
|
||||
|
||||
|
||||
#include "target_arch.h"
|
||||
|
||||
// #define DEBUG_PRINTF(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define DEBUG_PRINTF(...)
|
||||
|
||||
#define TARGET_DEFAULT_CPU_MODEL "any"
|
||||
|
||||
#define TARGET_CPU_RESET(cpu)
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
extern pthread_mutex_t ras_mtx;
|
||||
extern pthread_cond_t ras_cond;
|
||||
extern pthread_t ras_thread;
|
||||
extern bool ras_thread_set;
|
||||
#endif
|
||||
|
||||
static inline void target_cpu_init(CPUARMState *env,
|
||||
struct target_pt_regs *regs)
|
||||
{
|
||||
int i;
|
||||
|
||||
cpsr_write(env, regs->uregs[16], 0xffffffff, CPSRWriteRaw);
|
||||
for (i = 0; i < 16; i++) {
|
||||
env->regs[i] = regs->uregs[i];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void target_cpu_loop(CPUARMState *env)
|
||||
{
|
||||
int trapnr;
|
||||
target_siginfo_t info;
|
||||
unsigned int n;
|
||||
uint32_t addr;
|
||||
CPUState *cs = env_cpu(env);
|
||||
|
||||
for (;;) {
|
||||
cpu_exec_start(cs);
|
||||
trapnr = cpu_exec(cs);
|
||||
cpu_exec_end(cs);
|
||||
process_queued_cpu_work(cs);
|
||||
switch (trapnr) {
|
||||
case EXCP_UDEF:
|
||||
{
|
||||
/* See arm/arm/undefined.c undefinedinstruction(); */
|
||||
info.si_addr = env->regs[15];
|
||||
|
||||
/*
|
||||
* Make sure the PC is correctly aligned. (It should
|
||||
* be.)
|
||||
*/
|
||||
if ((info.si_addr & 3) != 0) {
|
||||
info.si_signo = TARGET_SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_ILLADR;
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
} else {
|
||||
int rc = 0;
|
||||
#ifdef NOT_YET
|
||||
uint32_t opcode;
|
||||
|
||||
/*
|
||||
* Get the opcode.
|
||||
*
|
||||
* FIXME - what to do if get_user() fails?
|
||||
*/
|
||||
get_user_u32(opcode, env->regs[15]);
|
||||
|
||||
/* Check the opcode with CP handlers we may have. */
|
||||
rc = EmulateAll(opcode, &ts-fpa, env);
|
||||
#endif /* NOT_YET */
|
||||
if (rc == 0) {
|
||||
/* illegal instruction */
|
||||
info.si_signo = TARGET_SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_ILLOPC;
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EXCP_SWI:
|
||||
case EXCP_BKPT:
|
||||
{
|
||||
unsigned int insn;
|
||||
#ifdef FREEBSD_ARM_OABI
|
||||
env->eabi = 0;
|
||||
#else
|
||||
env->eabi = 1;
|
||||
#endif
|
||||
/*
|
||||
* system call
|
||||
* See arm/arm/trap.c cpu_fetch_syscall_args()
|
||||
*/
|
||||
if (trapnr == EXCP_BKPT) {
|
||||
if (env->thumb) {
|
||||
if (env->eabi) {
|
||||
n = env->regs[7];
|
||||
} else {
|
||||
/* FIXME - what to do if get_user() fails? */
|
||||
get_user_u16(insn, env->regs[15]);
|
||||
n = insn & 0xff;
|
||||
}
|
||||
env->regs[15] += 2;
|
||||
} else {
|
||||
if (env->eabi) {
|
||||
n = env->regs[7];
|
||||
} else {
|
||||
/* FIXME - what to do if get_user() fails? */
|
||||
get_user_u32(insn, env->regs[15]);
|
||||
n = (insn & 0xf) | ((insn >> 4) & 0xff0);
|
||||
}
|
||||
env->regs[15] += 4;
|
||||
}
|
||||
} else { /* trapnr != EXCP_BKPT */
|
||||
if (env->thumb) {
|
||||
if (env->eabi) {
|
||||
n = env->regs[7];
|
||||
} else {
|
||||
/* FIXME - what to do if get_user() fails? */
|
||||
get_user_u16(insn, env->regs[15] - 2);
|
||||
n = insn & 0xff;
|
||||
}
|
||||
} else {
|
||||
if (env->eabi) {
|
||||
n = env->regs[7];
|
||||
} else {
|
||||
/* FIXME - what to do if get_user() fails? */
|
||||
get_user_u32(insn, env->regs[15] - 4);
|
||||
n = insn & 0xffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
DEBUG_PRINTF("AVANT CALL %d\n", n);
|
||||
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;
|
||||
|
||||
/* See arm/arm/trap.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) {
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
syscall_nr = env->regs[1];
|
||||
#else
|
||||
syscall_nr = env->regs[0];
|
||||
#endif
|
||||
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()
|
||||
*/
|
||||
/* XXX armeb may need some extra magic here */
|
||||
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; */
|
||||
}
|
||||
} /* else if (bsd_type == target_openbsd)... */
|
||||
else {
|
||||
fprintf(stderr, "qemu: bsd_type (= %d) syscall "
|
||||
"not supported\n", bsd_type);
|
||||
}
|
||||
DEBUG_PRINTF("APRES CALL\n");
|
||||
}
|
||||
break;
|
||||
case EXCP_INTERRUPT:
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
case EXCP_PREFETCH_ABORT:
|
||||
/* See arm/arm/trap.c prefetch_abort_handler() */
|
||||
addr = env->exception.vaddress;
|
||||
goto do_segv;
|
||||
case EXCP_DATA_ABORT:
|
||||
/* See arm/arm/trap.c data_abort_handler() */
|
||||
addr = env->exception.vaddress;
|
||||
#ifdef __FreeBSD__
|
||||
if (addr == 0xffff1000) { /* ARM_TP_ADDRESS */
|
||||
unsigned int insn;
|
||||
int rd;
|
||||
|
||||
get_user_u32(insn, env->regs[15]);
|
||||
/* Assume it is always either a load of a store, bogus, but probably good enough */
|
||||
rd = (insn >> 12) & 0xf;
|
||||
if (insn & (1 << 20)) {
|
||||
/* Load */
|
||||
env->regs[rd] = target_cpu_get_tls(env);
|
||||
} else {
|
||||
/* Store */
|
||||
target_cpu_set_tls(env, env->regs[rd]);
|
||||
}
|
||||
env->regs[15] += 4;
|
||||
break;
|
||||
|
||||
|
||||
} else if (addr == 0xffff1004 || addr == 0xffff1008) { /* ARM_RAS_START || ARM_RAS_END */
|
||||
int rd;
|
||||
unsigned int insn;
|
||||
|
||||
get_user_u32(insn, env->regs[15]);
|
||||
rd = (insn >> 12) & 0xf;
|
||||
|
||||
if (!(insn & (1 << 20)) && addr == 0xffff1004) {
|
||||
/* Store */
|
||||
pthread_mutex_lock(&ras_mtx);
|
||||
while (ras_thread_set && !pthread_equal(pthread_self(), ras_thread))
|
||||
pthread_cond_wait(&ras_cond, &ras_mtx);
|
||||
if (env->regs[rd] == 0) {
|
||||
ras_thread_set = 0;
|
||||
pthread_cond_signal(&ras_cond);
|
||||
} else {
|
||||
ras_thread_set = 1;
|
||||
ras_thread = pthread_self();
|
||||
}
|
||||
pthread_mutex_unlock(&ras_mtx);
|
||||
}
|
||||
env->regs[15] += 4;
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
do_segv:
|
||||
{
|
||||
info.si_signo = TARGET_SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
/* XXX: check env->error_code */
|
||||
info.si_code = 0;
|
||||
info.si_addr = addr;
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
}
|
||||
break;
|
||||
case EXCP_DEBUG:
|
||||
{
|
||||
|
||||
info.si_signo = TARGET_SIGTRAP;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_TRAP_BRKPT;
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
}
|
||||
break;
|
||||
case EXCP_ATOMIC:
|
||||
cpu_exec_step_atomic(cs);
|
||||
break;
|
||||
case EXCP_YIELD:
|
||||
/* nothing to do here for user-mode, just resume guest code */
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
|
||||
trapnr);
|
||||
cpu_dump_state(cs, stderr, 0);
|
||||
abort();
|
||||
} /* switch() */
|
||||
process_pending_signals(env);
|
||||
} /* for (;;) */
|
||||
}
|
||||
|
||||
static inline void target_cpu_clone_regs(CPUARMState *env, target_ulong newsp)
|
||||
{
|
||||
if (newsp)
|
||||
env->regs[13] = newsp;
|
||||
env->regs[0] = 0;
|
||||
}
|
||||
|
||||
static inline void target_cpu_reset(CPUArchState *cpu)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* !_TARGET_ARCH_CPU_H */
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* arm ELF 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 _TARGET_ARCH_ELF_H_
|
||||
#define _TARGET_ARCH_ELF_H_
|
||||
|
||||
#define ELF_START_MMAP 0x80000000
|
||||
#define ELF_ET_DYN_LOAD_ADDR 0x500000
|
||||
|
||||
#define elf_check_arch(x) ( (x) == EM_ARM )
|
||||
|
||||
#define ELF_CLASS ELFCLASS32
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
#define ELF_DATA ELFDATA2MSB
|
||||
#else
|
||||
#define ELF_DATA ELFDATA2LSB
|
||||
#endif
|
||||
#define ELF_ARCH EM_ARM
|
||||
|
||||
#define USE_ELF_CORE_DUMP
|
||||
#define ELF_EXEC_PAGESIZE 4096
|
||||
|
||||
enum
|
||||
{
|
||||
ARM_HWCAP_ARM_SWP = 1 << 0,
|
||||
ARM_HWCAP_ARM_HALF = 1 << 1,
|
||||
ARM_HWCAP_ARM_THUMB = 1 << 2,
|
||||
ARM_HWCAP_ARM_26BIT = 1 << 3,
|
||||
ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
|
||||
ARM_HWCAP_ARM_FPA = 1 << 5,
|
||||
ARM_HWCAP_ARM_VFP = 1 << 6,
|
||||
ARM_HWCAP_ARM_EDSP = 1 << 7,
|
||||
ARM_HWCAP_ARM_VFPv3 = 1 << 13,
|
||||
ARM_HWCAP_ARM_VFPv4 = 1 << 16,
|
||||
};
|
||||
|
||||
#define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF \
|
||||
| ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT \
|
||||
| ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP)
|
||||
|
||||
|
||||
#endif /* _TARGET_ARCH_ELF_H_ */
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* FreeBSD arm register structures
|
||||
*
|
||||
* Copyright (c) 2015 Stacey Son
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 _TARGET_ARCH_REG_H_
|
||||
#define _TARGET_ARCH_REG_H_
|
||||
|
||||
/* See sys/arm/include/reg.h */
|
||||
typedef struct target_reg {
|
||||
uint32_t r[13];
|
||||
uint32_t r_sp;
|
||||
uint32_t r_lr;
|
||||
uint32_t r_pc;
|
||||
uint32_t r_cpsr;
|
||||
} target_reg_t;
|
||||
|
||||
typedef struct target_fp_reg {
|
||||
uint32_t fp_exponent;
|
||||
uint32_t fp_mantissa_hi;
|
||||
u_int32_t fp_mantissa_lo;
|
||||
} target_fp_reg_t;
|
||||
|
||||
typedef struct target_fpreg {
|
||||
uint32_t fpr_fpsr;
|
||||
target_fp_reg_t fpr[8];
|
||||
} target_fpreg_t;
|
||||
|
||||
#define tswapreg(ptr) tswapal(ptr)
|
||||
|
||||
static inline void target_copy_regs(target_reg_t *regs, const CPUARMState *env)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 13; i++)
|
||||
regs->r[i] = tswapreg(env->regs[i + 1]);
|
||||
regs->r_sp = tswapreg(env->regs[13]);
|
||||
regs->r_lr = tswapreg(env->regs[14]);
|
||||
regs->r_pc = tswapreg(env->regs[15]);
|
||||
regs->r_cpsr = tswapreg(cpsr_read((CPUARMState *)env));
|
||||
}
|
||||
|
||||
#undef tswapreg
|
||||
|
||||
#endif /* !_TARGET_ARCH_REG_H_ */
|
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
* arm signal definitions
|
||||
*
|
||||
*
|
||||
* 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 _TARGET_ARCH_SIGNAL_H_
|
||||
#define _TARGET_ARCH_SIGNAL_H_
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
#define TARGET_REG_R0 0
|
||||
#define TARGET_REG_R1 1
|
||||
#define TARGET_REG_R2 2
|
||||
#define TARGET_REG_R3 3
|
||||
#define TARGET_REG_R4 4
|
||||
#define TARGET_REG_R5 5
|
||||
#define TARGET_REG_R6 6
|
||||
#define TARGET_REG_R7 7
|
||||
#define TARGET_REG_R8 8
|
||||
#define TARGET_REG_R9 9
|
||||
#define TARGET_REG_R10 10
|
||||
#define TARGET_REG_R11 11
|
||||
#define TARGET_REG_R12 12
|
||||
#define TARGET_REG_R13 13
|
||||
#define TARGET_REG_R14 14
|
||||
#define TARGET_REG_R15 15
|
||||
#define TARGET_REG_CPSR 16
|
||||
#define TARGET__NGREG 17
|
||||
/* Convenience synonyms */
|
||||
#define TARGET_REG_FP TARGET_REG_R11
|
||||
#define TARGET_REG_SP TARGET_REG_R13
|
||||
#define TARGET_REG_LR TARGET_REG_R14
|
||||
#define TARGET_REG_PC TARGET_REG_R15
|
||||
|
||||
#define TARGET_INSN_SIZE 4 /* arm instruction size */
|
||||
|
||||
/* Size of the signal trampolin code. See _sigtramp(). */
|
||||
#define TARGET_SZSIGCODE ((abi_ulong)(9 * TARGET_INSN_SIZE))
|
||||
|
||||
/* compare to arm/include/_limits.h */
|
||||
#define TARGET_MINSIGSTKSZ (1024 * 4) /* min sig stack size */
|
||||
#define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) /* recommended size */
|
||||
|
||||
/* arm/arm/machdep.c */
|
||||
#define TARGET_MC_GET_CLEAR_RET 0x0001
|
||||
#define TARGET_MC_ADD_MAGIC 0x0002
|
||||
#define TARGET_MC_SET_ONSTACK 0x0004
|
||||
|
||||
struct target_sigcontext {
|
||||
target_sigset_t sc_mask; /* signal mask to retstore */
|
||||
int32_t sc_onstack; /* sigstack state to restore */
|
||||
abi_long sc_pc; /* pc at time of signal */
|
||||
abi_long sc_reg[32]; /* processor regs 0 to 31 */
|
||||
abi_long mullo, mulhi; /* mullo and mulhi registers */
|
||||
int32_t sc_fpused; /* fp has been used */
|
||||
abi_long sc_fpregs[33]; /* fp regs 0 to 31 & csr */
|
||||
abi_long sc_fpc_eir; /* fp exception instr reg */
|
||||
/* int32_t reserved[8]; */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t __fp_fpsr;
|
||||
struct {
|
||||
uint32_t __fp_exponent;
|
||||
uint32_t __fp_mantissa_hi;
|
||||
uint32_t __fp_mantissa_lo;
|
||||
} __fp_fr[8];
|
||||
} target__fpregset_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t __vfp_fpscr;
|
||||
uint32_t __vfp_fstmx[33];
|
||||
uint32_t __vfp_fpsid;
|
||||
} target__vfpregset_t;
|
||||
|
||||
typedef struct target_mcontext {
|
||||
uint32_t __gregs[TARGET__NGREG];
|
||||
union {
|
||||
target__fpregset_t __fpregs;
|
||||
target__vfpregset_t __vfpregs;
|
||||
} __fpu;
|
||||
} target_mcontext_t;
|
||||
|
||||
typedef struct target_ucontext {
|
||||
target_sigset_t uc_sigmask;
|
||||
target_mcontext_t uc_mcontext;
|
||||
abi_ulong uc_link;
|
||||
target_stack_t uc_stack;
|
||||
int32_t uc_flags;
|
||||
int32_t __spare__[4];
|
||||
} target_ucontext_t;
|
||||
|
||||
struct target_sigframe {
|
||||
target_siginfo_t sf_si; /* saved siginfo */
|
||||
target_ucontext_t sf_uc; /* saved ucontext */
|
||||
};
|
||||
|
||||
|
||||
/* compare to sys/arm/include/frame.h */
|
||||
struct target_trapframe {
|
||||
abi_ulong tf_spsr; /* Zero on arm26 */
|
||||
abi_ulong tf_r0;
|
||||
abi_ulong tf_r1;
|
||||
abi_ulong tf_r2;
|
||||
abi_ulong tf_r3;
|
||||
abi_ulong tf_r4;
|
||||
abi_ulong tf_r5;
|
||||
abi_ulong tf_r6;
|
||||
abi_ulong tf_r7;
|
||||
abi_ulong tf_r8;
|
||||
abi_ulong tf_r9;
|
||||
abi_ulong tf_r10;
|
||||
abi_ulong tf_r11;
|
||||
abi_ulong tf_r12;
|
||||
abi_ulong tf_usr_sp;
|
||||
abi_ulong tf_usr_lr;
|
||||
abi_ulong tf_svc_sp; /* Not used on arm26 */
|
||||
abi_ulong tf_svc_lr; /* Not used on arm26 */
|
||||
abi_ulong tf_pc;
|
||||
};
|
||||
|
||||
/*
|
||||
* Compare to arm/arm/machdep.c sendsig()
|
||||
* Assumes that target stack frame memory is locked.
|
||||
*/
|
||||
static inline abi_long
|
||||
set_sigtramp_args(CPUARMState *regs, int sig, struct target_sigframe *frame,
|
||||
abi_ulong frame_addr, struct target_sigaction *ka)
|
||||
{
|
||||
/*
|
||||
* Arguments to signal handler:
|
||||
* r0 = signal number
|
||||
* r1 = siginfo pointer
|
||||
* r2 = ucontext pointer
|
||||
* r5 = ucontext pointer
|
||||
* pc = signal handler pointer
|
||||
* sp = sigframe struct pointer
|
||||
* lr = sigtramp at base of user stack
|
||||
*/
|
||||
|
||||
regs->regs[0] = sig;
|
||||
regs->regs[1] = frame_addr +
|
||||
offsetof(struct target_sigframe, sf_si);
|
||||
regs->regs[2] = frame_addr +
|
||||
offsetof(struct target_sigframe, sf_uc);
|
||||
|
||||
/* the trampoline uses r5 as the uc address */
|
||||
regs->regs[5] = frame_addr +
|
||||
offsetof(struct target_sigframe, sf_uc);
|
||||
regs->regs[TARGET_REG_PC] = ka->_sa_handler;
|
||||
regs->regs[TARGET_REG_SP] = frame_addr;
|
||||
regs->regs[TARGET_REG_LR] = TARGET_PS_STRINGS - TARGET_SZSIGCODE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare to arm/arm/machdep.c get_mcontext()
|
||||
* Assumes that the memory is locked if mcp points to user memory.
|
||||
*/
|
||||
static inline abi_long get_mcontext(CPUARMState *regs, target_mcontext_t *mcp,
|
||||
int flags)
|
||||
{
|
||||
int err = 0;
|
||||
uint32_t *gr = mcp->__gregs;
|
||||
|
||||
gr[TARGET_REG_CPSR] = tswap32(cpsr_read(regs));
|
||||
if (flags & TARGET_MC_GET_CLEAR_RET) {
|
||||
gr[TARGET_REG_R0] = 0;
|
||||
gr[TARGET_REG_CPSR] &= ~CPSR_C;
|
||||
} else {
|
||||
gr[TARGET_REG_R0] = tswap32(regs->regs[0]);
|
||||
}
|
||||
|
||||
gr[TARGET_REG_R1] = tswap32(regs->regs[1]);
|
||||
gr[TARGET_REG_R2] = tswap32(regs->regs[2]);
|
||||
gr[TARGET_REG_R3] = tswap32(regs->regs[3]);
|
||||
gr[TARGET_REG_R4] = tswap32(regs->regs[4]);
|
||||
gr[TARGET_REG_R5] = tswap32(regs->regs[5]);
|
||||
gr[TARGET_REG_R6] = tswap32(regs->regs[6]);
|
||||
gr[TARGET_REG_R7] = tswap32(regs->regs[7]);
|
||||
gr[TARGET_REG_R8] = tswap32(regs->regs[8]);
|
||||
gr[TARGET_REG_R9] = tswap32(regs->regs[9]);
|
||||
gr[TARGET_REG_R10] = tswap32(regs->regs[10]);
|
||||
gr[TARGET_REG_R11] = tswap32(regs->regs[11]);
|
||||
gr[TARGET_REG_R12] = tswap32(regs->regs[12]);
|
||||
|
||||
gr[TARGET_REG_SP] = tswap32(regs->regs[13]);
|
||||
gr[TARGET_REG_LR] = tswap32(regs->regs[14]);
|
||||
gr[TARGET_REG_PC] = tswap32(regs->regs[15]);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Compare to arm/arm/machdep.c set_mcontext() */
|
||||
static inline abi_long set_mcontext(CPUARMState *regs, target_mcontext_t *mcp,
|
||||
int srflag)
|
||||
{
|
||||
int err = 0;
|
||||
const uint32_t *gr = mcp->__gregs;
|
||||
uint32_t cpsr;
|
||||
|
||||
regs->regs[0] = tswap32(gr[TARGET_REG_R0]);
|
||||
regs->regs[1] = tswap32(gr[TARGET_REG_R1]);
|
||||
regs->regs[2] = tswap32(gr[TARGET_REG_R2]);
|
||||
regs->regs[3] = tswap32(gr[TARGET_REG_R3]);
|
||||
regs->regs[4] = tswap32(gr[TARGET_REG_R4]);
|
||||
regs->regs[5] = tswap32(gr[TARGET_REG_R5]);
|
||||
regs->regs[6] = tswap32(gr[TARGET_REG_R6]);
|
||||
regs->regs[7] = tswap32(gr[TARGET_REG_R7]);
|
||||
regs->regs[8] = tswap32(gr[TARGET_REG_R8]);
|
||||
regs->regs[9] = tswap32(gr[TARGET_REG_R9]);
|
||||
regs->regs[10] = tswap32(gr[TARGET_REG_R10]);
|
||||
regs->regs[11] = tswap32(gr[TARGET_REG_R11]);
|
||||
regs->regs[12] = tswap32(gr[TARGET_REG_R12]);
|
||||
|
||||
regs->regs[13] = tswap32(gr[TARGET_REG_SP]);
|
||||
regs->regs[14] = tswap32(gr[TARGET_REG_LR]);
|
||||
regs->regs[15] = tswap32(gr[TARGET_REG_PC]);
|
||||
cpsr = tswap32(gr[TARGET_REG_CPSR]);
|
||||
cpsr_write(regs, cpsr, CPSR_USER | CPSR_EXEC, CPSRWriteByInstr);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Compare to arm/arm/machdep.c sys_sigreturn() */
|
||||
static inline abi_long get_ucontext_sigreturn(CPUARMState *regs,
|
||||
abi_ulong target_sf, abi_ulong *target_uc)
|
||||
{
|
||||
uint32_t cpsr = cpsr_read(regs);
|
||||
|
||||
*target_uc = 0;
|
||||
|
||||
if ((cpsr & CPSR_M) != ARM_CPU_MODE_USR ||
|
||||
(cpsr & (CPSR_I | CPSR_F)) != 0) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
|
||||
*target_uc = target_sf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif /* !_TARGET_ARCH_SIGNAL_H_ */
|
|
@ -0,0 +1,34 @@
|
|||
|
||||
#ifndef _TARGET_ARCH_SIGTRAMP_H_
|
||||
#define _TARGET_ARCH_SIGTRAMP_H_
|
||||
|
||||
/* Compare to arm/arm/locore.S ENTRY_NP(sigcode) */
|
||||
static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
|
||||
unsigned sys_sigreturn)
|
||||
{
|
||||
int i;
|
||||
uint32_t sys_exit = TARGET_FREEBSD_NR_exit;
|
||||
/*
|
||||
* The code has to load r7 manually rather than using
|
||||
* "ldr r7, =SYS_return to make sure the size of the
|
||||
* code is correct.
|
||||
*/
|
||||
uint32_t sigtramp_code[] = {
|
||||
/* 1 */ 0xE1A0000D, /* mov r0, sp */
|
||||
/* 2 */ 0xE2800000 + sigf_uc, /* add r0, r0, #SIGF_UC */
|
||||
/* 3 */ 0xE59F700C, /* ldr r7, [pc, #12] */
|
||||
/* 4 */ 0xEF000000 + sys_sigreturn, /* swi (SYS_sigreturn) */
|
||||
/* 5 */ 0xE59F7008, /* ldr r7, [pc, #8] */
|
||||
/* 6 */ 0xEF000000 + sys_exit, /* swi (SYS_exit)*/
|
||||
/* 7 */ 0xEAFFFFFA, /* b . -16 */
|
||||
/* 8 */ sys_sigreturn,
|
||||
/* 9 */ sys_exit
|
||||
};
|
||||
|
||||
for (i = 0; i < 9; i++) {
|
||||
tswap32s(&sigtramp_code[i]);
|
||||
}
|
||||
|
||||
return memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE);
|
||||
}
|
||||
#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
|
|
@ -17,8 +17,8 @@
|
|||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef BSD_USER_ARCH_SYSARCH_H_
|
||||
#define BSD_USER_ARCH_SYSARCH_H_
|
||||
#ifndef __ARCH_SYSARCH_H_
|
||||
#define __ARCH_SYSARCH_H_
|
||||
|
||||
#include "target_syscall.h"
|
||||
#include "target_arch.h"
|
||||
|
@ -75,4 +75,4 @@ static inline void do_freebsd_arch_print_sysarch(
|
|||
}
|
||||
}
|
||||
|
||||
#endif /*!BSD_USER_ARCH_SYSARCH_H_ */
|
||||
#endif /*!__ARCH_SYSARCH_H_ */
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* arm thread support
|
||||
*
|
||||
* 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 _TARGET_ARCH_THREAD_H_
|
||||
#define _TARGET_ARCH_THREAD_H_
|
||||
|
||||
/* Compare to arm/arm/vm_machdep.c cpu_set_upcall_kse() */
|
||||
static inline void target_thread_set_upcall(CPUARMState *regs, abi_ulong entry,
|
||||
abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
|
||||
{
|
||||
abi_ulong sp;
|
||||
|
||||
/*
|
||||
* Make sure the stack is properly aligned.
|
||||
* arm/include/param.h (STACKLIGN() macro)
|
||||
*/
|
||||
sp = (u_int)((stack_base + stack_size) -
|
||||
sizeof(struct target_trapframe)) & ~0x7;
|
||||
|
||||
/* sp = stack base */
|
||||
regs->regs[13] = sp;
|
||||
/* pc = start function entry */
|
||||
regs->regs[15] = entry & 0xfffffffe;
|
||||
/* r0 = arg */
|
||||
regs->regs[0] = arg;
|
||||
regs->spsr = ARM_CPU_MODE_USR;
|
||||
}
|
||||
|
||||
static inline void target_thread_init(struct target_pt_regs *regs,
|
||||
struct image_info *infop)
|
||||
{
|
||||
abi_long stack = infop->start_stack;
|
||||
memset(regs, 0, sizeof(*regs));
|
||||
regs->ARM_cpsr = 0x10;
|
||||
if (infop->entry & 1)
|
||||
regs->ARM_cpsr |= CPSR_T;
|
||||
regs->ARM_pc = infop->entry & 0xfffffffe;
|
||||
regs->ARM_sp = infop->start_stack;
|
||||
if (bsd_type == target_freebsd) {
|
||||
regs->ARM_lr = infop->entry & 0xfffffffe;
|
||||
}
|
||||
/* FIXME - what to for failure of get_user()? */
|
||||
get_user_ual(regs->ARM_r2, stack + 8); /* envp */
|
||||
get_user_ual(regs->ARM_r1, stack + 4); /* envp */
|
||||
/* XXX: it seems that r0 is zeroed after ! */
|
||||
regs->ARM_r0 = 0;
|
||||
/* For uClinux PIC binaries. */
|
||||
/* XXX: Linux does this only on ARM with no MMU (do we care ?) */
|
||||
regs->ARM_r10 = infop->start_data;
|
||||
}
|
||||
|
||||
#endif /* !_TARGET_ARCH_THREAD_H_ */
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* arm VM parameters 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 _TARGET_ARCH_VMPARAM_H_
|
||||
#define _TARGET_ARCH_VMPARAM_H_
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
/* compare to sys/arm/include/vmparam.h */
|
||||
#define TARGET_MAXTSIZ (64 * MiB) /* max text size */
|
||||
#define TARGET_DFLDSIZ (128 * MiB) /* initial data size limit */
|
||||
#define TARGET_MAXDSIZ (512 * MiB) /* max data size */
|
||||
#define TARGET_DFLSSIZ (4 * MiB) /* initial stack size limit */
|
||||
#define TARGET_MAXSSIZ (64 * MiB) /* max stack size */
|
||||
#define TARGET_SGROWSIZ (128 * KiB) /* amount to grow stack */
|
||||
|
||||
#define TARGET_RESERVED_VA 0xf7000000
|
||||
|
||||
/* KERNBASE - 512 MB */
|
||||
#define TARGET_VM_MAXUSER_ADDRESS (0xc0000000 - (512 * MiB))
|
||||
#define TARGET_USRSTACK TARGET_VM_MAXUSER_ADDRESS
|
||||
|
||||
static inline abi_ulong get_sp_from_cpustate(CPUARMState *state)
|
||||
{
|
||||
return state->regs[13]; /* sp */
|
||||
}
|
||||
|
||||
static inline void set_second_rval(CPUARMState *state, abi_ulong retval2)
|
||||
{
|
||||
state->regs[1] = retval2;
|
||||
}
|
||||
|
||||
#endif /* ! _TARGET_ARCH_VMPARAM_H_ */
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef BSD_USER_ARCH_SYSCALL_H_
|
||||
#define BSD_USER_ARCH_SYSCALL_H_
|
||||
#ifndef __ARCH_SYSCALL_H_
|
||||
#define __ARCH_SYSCALL_H_
|
||||
|
||||
struct target_pt_regs {
|
||||
abi_long uregs[17];
|
||||
|
@ -33,4 +33,4 @@ struct target_pt_regs {
|
|||
#define TARGET_HW_MACHINE "arm"
|
||||
#define TARGET_HW_MACHINE_ARCH "armv6"
|
||||
|
||||
#endif /* !BSD_USER_ARCH_SYSCALL_H_ */
|
||||
#endif /* !__ARCH_SYSCALL_H_ */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,563 @@
|
|||
/*
|
||||
* BSD ioctl(2) emulation
|
||||
*
|
||||
* Copyright (c) 2013-15 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/>.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/disk.h>
|
||||
#include <sys/ioccom.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/_termios.h>
|
||||
#include <sys/ttycom.h>
|
||||
#include <sys/filio.h>
|
||||
|
||||
#include <crypto/cryptodev.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_var.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/route.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_gif.h>
|
||||
#include <net/if_gre.h>
|
||||
#include <net/if_lagg.h>
|
||||
#include <net/if_media.h>
|
||||
#include <net/pfvar.h>
|
||||
#include <net/if_pfsync.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <netinet/icmp6.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip_carp.h>
|
||||
#include <netinet6/in6_var.h>
|
||||
#include <netinet6/nd6.h>
|
||||
#include <net80211/ieee80211_ioctl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "qemu.h"
|
||||
#include "qemu-common.h"
|
||||
|
||||
#include "bsd-ioctl.h"
|
||||
#include "os-ioctl-cryptodev.h"
|
||||
#include "os-ioctl-disk.h"
|
||||
#include "os-ioctl-filio.h"
|
||||
#include "os-ioctl-in6_var.h"
|
||||
#include "os-ioctl-sockio.h"
|
||||
#include "os-ioctl-ttycom.h"
|
||||
|
||||
static const bitmask_transtbl iflag_tbl[] = {
|
||||
{ TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
|
||||
{ TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
|
||||
{ TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
|
||||
{ TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
|
||||
{ TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
|
||||
{ TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
|
||||
{ TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
|
||||
{ TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
|
||||
{ TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
|
||||
{ TARGET_IXON, TARGET_IXON, IXON, IXON },
|
||||
{ TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
|
||||
#ifdef IXANY
|
||||
{ TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
|
||||
#endif
|
||||
#ifdef IMAXBEL
|
||||
{ TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
|
||||
#endif
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
static const bitmask_transtbl oflag_tbl[] = {
|
||||
{ TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
|
||||
#ifdef ONLCR
|
||||
{ TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
|
||||
#endif
|
||||
#ifdef TABDLY
|
||||
{ TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
|
||||
{ TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
|
||||
#endif
|
||||
#ifdef ONOEOT
|
||||
{ TARGET_ONOEOT, TARGET_ONOEOT, ONOEOT, ONOEOT },
|
||||
#endif
|
||||
#ifdef OCRNL
|
||||
{ TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
|
||||
#endif
|
||||
#ifdef ONOCR
|
||||
{ TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
|
||||
#endif
|
||||
#ifdef ONLRET
|
||||
{ TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
|
||||
#endif
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
static const bitmask_transtbl cflag_tbl[] = {
|
||||
#ifdef CIGNORE
|
||||
{ TARGET_CIGNORE, TARGET_CIGNORE, CIGNORE, CIGNORE },
|
||||
#endif
|
||||
{ TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
|
||||
{ TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
|
||||
{ TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
|
||||
{ TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
|
||||
{ TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
|
||||
{ TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
|
||||
{ TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
|
||||
{ TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
|
||||
{ TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
|
||||
{ TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
|
||||
#ifdef CCTS_OFLOW
|
||||
{ TARGET_CCTS_OFLOW, TARGET_CCTS_OFLOW, CCTS_OFLOW, CCTS_OFLOW },
|
||||
#endif
|
||||
#ifdef CRTSCTS
|
||||
{ TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
|
||||
#endif
|
||||
#ifdef CRTS_IFLOW
|
||||
{ TARGET_CRTS_IFLOW, TARGET_CRTS_IFLOW, CRTS_IFLOW, CRTS_IFLOW },
|
||||
#endif
|
||||
#ifdef CDTS_IFLOW
|
||||
{ TARGET_CDTR_IFLOW, TARGET_CDTR_IFLOW, CDTR_IFLOW, CDTR_IFLOW },
|
||||
#endif
|
||||
#ifdef CDSR_OFLOW
|
||||
{ TARGET_CDSR_OFLOW, TARGET_CDSR_OFLOW, CDSR_OFLOW, CDSR_OFLOW },
|
||||
#endif
|
||||
#ifdef CCAR_OFLOW
|
||||
{ TARGET_CCAR_OFLOW, TARGET_CCAR_OFLOW, CCAR_OFLOW, CCAR_OFLOW },
|
||||
#endif
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
static const bitmask_transtbl lflag_tbl[] = {
|
||||
#ifdef ECHOKE
|
||||
{ TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
|
||||
#endif
|
||||
{ TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
|
||||
{ TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
|
||||
{ TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
|
||||
{ TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
|
||||
#ifdef ECHOPRT
|
||||
{ TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
|
||||
#endif
|
||||
#ifdef ECHOCTL
|
||||
{ TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
|
||||
#endif
|
||||
{ TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
|
||||
{ TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
|
||||
#ifdef ALTWERASE
|
||||
{ TARGET_ALTWERASE, TARGET_ALTWERASE, ALTWERASE, ALTWERASE },
|
||||
#endif
|
||||
{ TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
|
||||
{ TARGET_EXTPROC, TARGET_EXTPROC, EXTPROC, EXTPROC },
|
||||
{ TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
|
||||
#ifdef FLUSHO
|
||||
{ TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
|
||||
#endif
|
||||
#ifdef NOKERNINFO
|
||||
{ TARGET_NOKERNINFO, TARGET_NOKERNINFO, NOKERNINFO, NOKERNINFO },
|
||||
#endif
|
||||
#ifdef PENDIN
|
||||
{ TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
|
||||
#endif
|
||||
{ TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
static void target_to_host_termios(void *dst, const void *src)
|
||||
{
|
||||
struct termios *host = dst;
|
||||
const struct target_termios *target = src;
|
||||
|
||||
host->c_iflag = target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
|
||||
host->c_oflag = target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
|
||||
host->c_cflag = target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
|
||||
host->c_lflag = target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
|
||||
|
||||
memset(host->c_cc, 0, sizeof(host->c_cc));
|
||||
host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
|
||||
host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
|
||||
#ifdef VEOL2
|
||||
host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
|
||||
#endif
|
||||
host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
|
||||
#ifdef VWERASE
|
||||
host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
|
||||
#endif
|
||||
host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
|
||||
#ifdef VREPRINT
|
||||
host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
|
||||
#endif
|
||||
#ifdef VERASE2
|
||||
host->c_cc[VERASE2] = target->c_cc[TARGET_VERASE2];
|
||||
#endif
|
||||
host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
|
||||
host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
|
||||
host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
|
||||
#ifdef VDSUSP
|
||||
host->c_cc[VDSUSP] = target->c_cc[TARGET_VDSUSP];
|
||||
#endif
|
||||
host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
|
||||
host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
|
||||
#ifdef VLNEXT
|
||||
host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
|
||||
#endif
|
||||
#ifdef VDISCARD
|
||||
host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
|
||||
#endif
|
||||
host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
|
||||
host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
|
||||
#ifdef VSTATUS
|
||||
host->c_cc[VSTATUS] = target->c_cc[TARGET_VSTATUS];
|
||||
#endif
|
||||
|
||||
host->c_ispeed = tswap32(target->c_ispeed);
|
||||
host->c_ospeed = tswap32(target->c_ospeed);
|
||||
}
|
||||
|
||||
static void host_to_target_termios(void *dst, const void *src)
|
||||
{
|
||||
struct target_termios *target = dst;
|
||||
const struct termios *host = src;
|
||||
|
||||
target->c_iflag = tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
|
||||
target->c_oflag = tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
|
||||
target->c_cflag = tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
|
||||
target->c_lflag = tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
|
||||
|
||||
memset(target->c_cc, 0, sizeof(target->c_cc));
|
||||
target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
|
||||
target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
|
||||
#ifdef VEOL2
|
||||
target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
|
||||
#endif
|
||||
target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
|
||||
#ifdef VWERASE
|
||||
target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
|
||||
#endif
|
||||
target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
|
||||
#ifdef VREPRINT
|
||||
target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
|
||||
#endif
|
||||
#ifdef VERASE2
|
||||
target->c_cc[TARGET_VERASE2] = host->c_cc[VERASE2];
|
||||
#endif
|
||||
target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
|
||||
target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
|
||||
target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
|
||||
#ifdef VDSUSP
|
||||
target->c_cc[TARGET_VDSUSP] = host->c_cc[VDSUSP];
|
||||
#endif
|
||||
target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
|
||||
target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
|
||||
#ifdef VLNEXT
|
||||
target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
|
||||
#endif
|
||||
#ifdef VDISCARD
|
||||
target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
|
||||
#endif
|
||||
target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
|
||||
target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
|
||||
#ifdef VSTATUS
|
||||
target->c_cc[TARGET_VSTATUS] = host->c_cc[VSTATUS];
|
||||
#endif
|
||||
|
||||
target->c_ispeed = tswap32(host->c_ispeed);
|
||||
target->c_ospeed = tswap32(host->c_ospeed);
|
||||
}
|
||||
|
||||
static const StructEntry struct_termios_def = {
|
||||
.convert = { host_to_target_termios, target_to_host_termios },
|
||||
.size = { sizeof(struct target_termios), sizeof(struct termios) },
|
||||
.align = { __alignof__(struct target_termios),
|
||||
__alignof__(struct termios) },
|
||||
};
|
||||
|
||||
|
||||
/* ioctl structure type definitions */
|
||||
#define STRUCT(name, ...) STRUCT_ ## name,
|
||||
#define STRUCT_SPECIAL(name) STRUCT_ ## name,
|
||||
enum {
|
||||
#include "os-ioctl-types.h"
|
||||
STRUCT_MAX
|
||||
};
|
||||
#undef STRUCT
|
||||
#undef STRUCT_SPECIAL
|
||||
|
||||
#define STRUCT(name, ...) \
|
||||
static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
|
||||
#define STRUCT_SPECIAL(name)
|
||||
#include "os-ioctl-types.h"
|
||||
#undef STRUCT
|
||||
#undef STRUCT_SPECIAL
|
||||
|
||||
|
||||
struct IOCTLEntry;
|
||||
|
||||
typedef abi_long do_ioctl_fn(const struct IOCTLEntry *ie, uint8_t *buf_temp,
|
||||
int fd, abi_long cmd, abi_long arg);
|
||||
|
||||
struct IOCTLEntry {
|
||||
unsigned int target_cmd;
|
||||
unsigned int host_cmd;
|
||||
const char *name;
|
||||
int access;
|
||||
do_ioctl_fn *do_ioctl;
|
||||
const argtype arg_type[5];
|
||||
};
|
||||
typedef struct IOCTLEntry IOCTLEntry;
|
||||
|
||||
#define MAX_STRUCT_SIZE 4096
|
||||
|
||||
static abi_long do_ioctl_unsupported(__unused const IOCTLEntry *ie,
|
||||
__unused uint8_t *buf_temp, __unused int fd,
|
||||
__unused abi_long cmd, __unused abi_long arg);
|
||||
|
||||
static abi_long do_ioctl_in6_ifreq_sockaddr_int(const IOCTLEntry *ie,
|
||||
uint8_t *buf_temp, int fd, abi_long cmd, abi_long arg);
|
||||
|
||||
static IOCTLEntry ioctl_entries[] = {
|
||||
#define IOC_ 0x0000
|
||||
#define IOC_R 0x0001
|
||||
#define IOC_W 0x0002
|
||||
#define IOC_RW (IOC_R | IOC_W)
|
||||
#define IOCTL(cmd, access, ...) \
|
||||
{ TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
|
||||
#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
|
||||
{ TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
|
||||
#define IOCTL_SPECIAL_UNIMPL(cmd, access, dofn, ...) \
|
||||
{ TARGET_ ## cmd, 0, #cmd, access, dofn, { __VA_ARGS__ } },
|
||||
#include "os-ioctl-cmds.h"
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
static void log_unsupported_ioctl(unsigned long cmd)
|
||||
{
|
||||
gemu_log("cmd=0x%08lx dir=", cmd);
|
||||
switch (cmd & IOC_DIRMASK) {
|
||||
case IOC_VOID:
|
||||
gemu_log("VOID ");
|
||||
break;
|
||||
case IOC_OUT:
|
||||
gemu_log("OUT ");
|
||||
break;
|
||||
case IOC_IN:
|
||||
gemu_log("IN ");
|
||||
break;
|
||||
case IOC_INOUT:
|
||||
gemu_log("INOUT");
|
||||
break;
|
||||
default:
|
||||
gemu_log("%01lx ???", (cmd & IOC_DIRMASK) >> 29);
|
||||
break;
|
||||
}
|
||||
gemu_log(" '%c' %3d %lu\n", (char)IOCGROUP(cmd), (int)(cmd & 0xff), IOCPARM_LEN(cmd));
|
||||
}
|
||||
|
||||
static abi_long do_ioctl_unsupported(__unused const IOCTLEntry *ie,
|
||||
__unused uint8_t *buf_temp, __unused int fd,
|
||||
__unused abi_long cmd, __unused abi_long arg)
|
||||
{
|
||||
|
||||
return -TARGET_ENXIO;
|
||||
}
|
||||
|
||||
static void target_to_host_sockaddr_in6(struct sockaddr_in6 *hsa_in6,
|
||||
struct target_sockaddr_in6 *tsa_in6)
|
||||
{
|
||||
|
||||
__get_user(hsa_in6->sin6_len, &tsa_in6->sin6_len);
|
||||
__get_user(hsa_in6->sin6_family, &tsa_in6->sin6_family);
|
||||
__get_user(hsa_in6->sin6_port, &tsa_in6->sin6_port);
|
||||
__get_user(hsa_in6->sin6_flowinfo, &tsa_in6->sin6_flowinfo);
|
||||
memcpy(&hsa_in6->sin6_addr, &tsa_in6->sin6_addr, 16);
|
||||
__get_user(hsa_in6->sin6_scope_id, &tsa_in6->sin6_scope_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* For ioctl()'s such as SIOCGIFAFLAG_IN6 and SIOCGIFALIFETIME_IN6 that
|
||||
* passes a struct sockaddr_in6 in and gets an int out using
|
||||
* struct in6_ifreq.
|
||||
*/
|
||||
static abi_long do_ioctl_in6_ifreq_sockaddr_int(const IOCTLEntry *ie,
|
||||
uint8_t *buf_temp, int fd, abi_long cmd, abi_long arg)
|
||||
{
|
||||
abi_long ret;
|
||||
struct target_in6_ifreq *tin6ifreq;
|
||||
struct target_sockaddr_in6 *tsa_in6;
|
||||
struct in6_ifreq hin6ifreq;
|
||||
struct sockaddr_in6 *hsa_in6 = &hin6ifreq.ifr_ifru.ifru_addr;
|
||||
|
||||
tin6ifreq = lock_user(VERIFY_WRITE, arg, sizeof (*tin6ifreq), 0);
|
||||
if (tin6ifreq == NULL)
|
||||
return -TARGET_EFAULT;
|
||||
memcpy(hin6ifreq.ifr_name, tin6ifreq->ifr_name, IFNAMSIZ);
|
||||
tsa_in6 = &tin6ifreq->ifr_ifru.ifru_addr;
|
||||
target_to_host_sockaddr_in6(hsa_in6, tsa_in6);
|
||||
|
||||
ret = get_errno(safe_ioctl(fd, ie->host_cmd, &hin6ifreq));
|
||||
if (!is_error(ret)) {
|
||||
put_user_s32(hin6ifreq.ifr_ifru.ifru_flags6,
|
||||
arg + offsetof(struct target_in6_ifreq, ifr_ifru.ifru_flags6));
|
||||
}
|
||||
unlock_user(tin6ifreq, arg, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
abi_long do_bsd_ioctl(int fd, abi_long cmd, abi_long arg)
|
||||
{
|
||||
const IOCTLEntry *ie;
|
||||
const argtype *arg_type;
|
||||
abi_long ret;
|
||||
uint8_t buf_temp[MAX_STRUCT_SIZE];
|
||||
int target_size;
|
||||
void *argptr;
|
||||
|
||||
ie = ioctl_entries;
|
||||
for (;;) {
|
||||
if (ie->target_cmd == 0) {
|
||||
gemu_log("Qemu unsupported ioctl: ");
|
||||
log_unsupported_ioctl(cmd);
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
if (ie->target_cmd == cmd) {
|
||||
break;
|
||||
}
|
||||
ie++;
|
||||
}
|
||||
arg_type = ie->arg_type;
|
||||
#if defined(DEBUG)
|
||||
gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
|
||||
#endif
|
||||
if (ie->do_ioctl) {
|
||||
return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
|
||||
}
|
||||
|
||||
switch (arg_type[0]) {
|
||||
case TYPE_NULL:
|
||||
/* no argument */
|
||||
ret = get_errno(safe_ioctl(fd, ie->host_cmd));
|
||||
break;
|
||||
|
||||
case TYPE_PTRVOID:
|
||||
case TYPE_INT:
|
||||
/* int argument */
|
||||
ret = get_errno(safe_ioctl(fd, ie->host_cmd, arg));
|
||||
break;
|
||||
|
||||
case TYPE_PTR:
|
||||
arg_type++;
|
||||
target_size = thunk_type_size(arg_type, 0);
|
||||
switch (ie->access) {
|
||||
case IOC_R:
|
||||
ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
|
||||
if (!is_error(ret)) {
|
||||
argptr = lock_user(VERIFY_WRITE, arg,
|
||||
target_size, 0);
|
||||
if (!argptr) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
thunk_convert(argptr, buf_temp, arg_type,
|
||||
THUNK_TARGET);
|
||||
unlock_user(argptr, arg, target_size);
|
||||
}
|
||||
break;
|
||||
|
||||
case IOC_W:
|
||||
argptr = lock_user(VERIFY_READ, arg, target_size, 1);
|
||||
if (!argptr) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
|
||||
unlock_user(argptr, arg, 0);
|
||||
ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
|
||||
break;
|
||||
|
||||
case IOC_RW:
|
||||
/* fallthrough */
|
||||
default:
|
||||
argptr = lock_user(VERIFY_READ, arg, target_size, 1);
|
||||
if (!argptr) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
|
||||
unlock_user(argptr, arg, 0);
|
||||
ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
|
||||
if (!is_error(ret)) {
|
||||
argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
|
||||
if (!argptr) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
|
||||
unlock_user(argptr, arg, target_size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
gemu_log("Qemu unknown ioctl: type=%d ", arg_type[0]);
|
||||
log_unsupported_ioctl(cmd);
|
||||
ret = -TARGET_ENOSYS;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void init_bsd_ioctl(void)
|
||||
{
|
||||
IOCTLEntry *ie;
|
||||
const argtype *arg_type;
|
||||
int size;
|
||||
|
||||
thunk_init(STRUCT_MAX);
|
||||
|
||||
#define STRUCT(name, ...) \
|
||||
thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
|
||||
#define STRUCT_SPECIAL(name) \
|
||||
thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
|
||||
#include "os-ioctl-types.h"
|
||||
#undef STRUCT
|
||||
#undef STRUCT_SPECIAL
|
||||
|
||||
/*
|
||||
* Patch the ioctl size if necessary using the fact that no
|
||||
* ioctl has all the bits at '1' in the size field
|
||||
* (IOCPARM_MAX - 1).
|
||||
*/
|
||||
ie = ioctl_entries;
|
||||
while (ie->target_cmd != 0) {
|
||||
if (((ie->target_cmd >> TARGET_IOCPARM_SHIFT) &
|
||||
TARGET_IOCPARM_MASK) == TARGET_IOCPARM_MASK) {
|
||||
arg_type = ie->arg_type;
|
||||
if (arg_type[0] != TYPE_PTR) {
|
||||
fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
|
||||
ie->target_cmd);
|
||||
exit(1);
|
||||
}
|
||||
arg_type++;
|
||||
size = thunk_type_size(arg_type, 0);
|
||||
ie->target_cmd = (ie->target_cmd &
|
||||
~(TARGET_IOCPARM_MASK << TARGET_IOCPARM_SHIFT)) |
|
||||
(size << TARGET_IOCPARM_SHIFT);
|
||||
}
|
||||
ie++;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* ioctl system call 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_IOCTL_H_
|
||||
#define __BSD_IOCTL_H_
|
||||
|
||||
abi_long do_bsd_ioctl(int fd, abi_long cmd, abi_long arg);
|
||||
void init_bsd_ioctl(void);
|
||||
|
||||
#endif /* !__BSD_IOCTL_H_ */
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* memory management system conversion routines
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
|
||||
#include "qemu.h"
|
||||
#include "qemu-bsd.h"
|
||||
|
||||
struct bsd_shm_regions bsd_shm_regions[N_BSD_SHM_REGIONS];
|
||||
|
||||
abi_ulong bsd_target_brk;
|
||||
abi_ulong bsd_target_original_brk;
|
||||
abi_ulong brk_page;
|
||||
|
||||
void target_set_brk(abi_ulong new_brk)
|
||||
{
|
||||
|
||||
bsd_target_original_brk = bsd_target_brk = HOST_PAGE_ALIGN(new_brk);
|
||||
brk_page = HOST_PAGE_ALIGN(bsd_target_brk);
|
||||
}
|
||||
|
||||
abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
|
||||
abi_ulong target_addr)
|
||||
{
|
||||
struct target_ipc_perm *target_ip;
|
||||
|
||||
if (!lock_user_struct(VERIFY_READ, target_ip, target_addr, 1)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__get_user(host_ip->cuid, &target_ip->cuid);
|
||||
__get_user(host_ip->cgid, &target_ip->cgid);
|
||||
__get_user(host_ip->uid, &target_ip->uid);
|
||||
__get_user(host_ip->gid, &target_ip->gid);
|
||||
__get_user(host_ip->mode, &target_ip->mode);
|
||||
__get_user(host_ip->seq, &target_ip->seq);
|
||||
__get_user(host_ip->key, &target_ip->key);
|
||||
unlock_user_struct(target_ip, target_addr, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long host_to_target_ipc_perm(abi_ulong target_addr,
|
||||
struct ipc_perm *host_ip)
|
||||
{
|
||||
struct target_ipc_perm *target_ip;
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_ip, target_addr, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__put_user(host_ip->cuid, &target_ip->cuid);
|
||||
__put_user(host_ip->cgid, &target_ip->cgid);
|
||||
__put_user(host_ip->uid, &target_ip->uid);
|
||||
__put_user(host_ip->gid, &target_ip->gid);
|
||||
__put_user(host_ip->mode, &target_ip->mode);
|
||||
__put_user(host_ip->seq, &target_ip->seq);
|
||||
__put_user(host_ip->key, &target_ip->key);
|
||||
unlock_user_struct(target_ip, target_addr, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
|
||||
abi_ulong target_addr)
|
||||
{
|
||||
struct target_shmid_ds *target_sd;
|
||||
|
||||
if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
|
||||
__get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
|
||||
__get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
|
||||
__get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
|
||||
__get_user(host_sd->shm_atime, &target_sd->shm_atime);
|
||||
__get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
|
||||
__get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
|
||||
unlock_user_struct(target_sd, target_addr, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long host_to_target_shmid_ds(abi_ulong target_addr,
|
||||
struct shmid_ds *host_sd)
|
||||
{
|
||||
struct target_shmid_ds *target_sd;
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm))) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
|
||||
__put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
|
||||
__put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
|
||||
__put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
|
||||
__put_user(host_sd->shm_atime, &target_sd->shm_atime);
|
||||
__put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
|
||||
__put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
|
||||
unlock_user_struct(target_sd, target_addr, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,441 @@
|
|||
/*
|
||||
* memory management system call shims and definitions
|
||||
*
|
||||
* Copyright (c) 2013-15 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/>.
|
||||
*/
|
||||
|
||||
/*--
|
||||
* Copyright (c) 1982, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _BSD_MMAN_H_
|
||||
#define _BSD_MMAN_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/shm.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "qemu-bsd.h"
|
||||
|
||||
extern struct bsd_shm_regions bsd_shm_regions[];
|
||||
extern abi_ulong bsd_target_brk;
|
||||
extern abi_ulong bsd_target_original_brk;
|
||||
extern abi_ulong brk_page;
|
||||
|
||||
/* mmap(2) */
|
||||
static inline abi_long do_bsd_mmap(void *cpu_env, abi_long arg1, abi_long arg2,
|
||||
abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6, abi_long arg7,
|
||||
abi_long arg8)
|
||||
{
|
||||
|
||||
if (regpairs_aligned(cpu_env) != 0) {
|
||||
arg6 = arg7;
|
||||
arg7 = arg8;
|
||||
}
|
||||
return get_errno(target_mmap(arg1, arg2, arg3,
|
||||
target_to_host_bitmask(arg4, mmap_flags_tbl), arg5,
|
||||
target_arg64(arg6, arg7)));
|
||||
}
|
||||
|
||||
/* munmap(2) */
|
||||
static inline abi_long do_bsd_munmap(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
|
||||
return get_errno(target_munmap(arg1, arg2));
|
||||
}
|
||||
|
||||
/* mprotect(2) */
|
||||
static inline abi_long do_bsd_mprotect(abi_long arg1, abi_long arg2,
|
||||
abi_long arg3)
|
||||
{
|
||||
|
||||
return get_errno(target_mprotect(arg1, arg2, arg3));
|
||||
}
|
||||
|
||||
/* msync(2) */
|
||||
static inline abi_long do_bsd_msync(abi_long addr, abi_long len, abi_long flags)
|
||||
{
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, addr, len)) {
|
||||
/* XXX Should be EFAULT, but FreeBSD seems to get this wrong. */
|
||||
return -TARGET_ENOMEM;
|
||||
}
|
||||
|
||||
return get_errno(msync(g2h_untagged(addr), len, flags));
|
||||
}
|
||||
|
||||
/* mlock(2) */
|
||||
static inline abi_long do_bsd_mlock(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
|
||||
return get_errno(mlock(g2h_untagged(arg1), arg2));
|
||||
}
|
||||
|
||||
/* munlock(2) */
|
||||
static inline abi_long do_bsd_munlock(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
|
||||
return get_errno(munlock(g2h_untagged(arg1), arg2));
|
||||
}
|
||||
|
||||
/* mlockall(2) */
|
||||
static inline abi_long do_bsd_mlockall(abi_long arg1)
|
||||
{
|
||||
|
||||
return get_errno(mlockall(arg1));
|
||||
}
|
||||
|
||||
/* munlockall(2) */
|
||||
static inline abi_long do_bsd_munlockall(void)
|
||||
{
|
||||
|
||||
return get_errno(munlockall());
|
||||
}
|
||||
|
||||
/* madvise(2) */
|
||||
static inline abi_long do_bsd_madvise(abi_long arg1, abi_long arg2,
|
||||
abi_long arg3)
|
||||
{
|
||||
/*
|
||||
* A straight passthrough may not be safe because qemu sometimes
|
||||
* turns private file-backed mapping into anonymous mappings. This
|
||||
* will break MADV_DONTNEED. This is a hint, so ignoring and returing
|
||||
* success is ok.
|
||||
*/
|
||||
return get_errno(0);
|
||||
}
|
||||
|
||||
/* minherit(2) */
|
||||
static inline abi_long do_bsd_minherit(abi_long addr, abi_long len,
|
||||
abi_long inherit)
|
||||
{
|
||||
|
||||
return get_errno(minherit(g2h_untagged(addr), len, inherit));
|
||||
}
|
||||
|
||||
/* mincore(2) */
|
||||
static inline abi_long do_bsd_mincore(abi_ulong target_addr, abi_ulong len,
|
||||
abi_ulong target_vec)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p, *a;
|
||||
|
||||
a = lock_user(VERIFY_WRITE, target_addr, len, 0);
|
||||
if (a == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
p = lock_user_string(target_vec);
|
||||
if (p == NULL) {
|
||||
unlock_user(a, target_addr, 0);
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(mincore(a, len, p));
|
||||
unlock_user(p, target_vec, ret);
|
||||
unlock_user(a, target_addr, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
|
||||
#define DEBUGF_BRK(message, args...)
|
||||
|
||||
/* do_brk() must return target values and target errnos. */
|
||||
static inline abi_long do_obreak(abi_ulong new_brk)
|
||||
{
|
||||
abi_long mapped_addr;
|
||||
int new_alloc_size;
|
||||
|
||||
DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
|
||||
|
||||
if (!new_brk) {
|
||||
DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", bsd_target_brk);
|
||||
return bsd_target_brk;
|
||||
}
|
||||
if (new_brk < bsd_target_original_brk) {
|
||||
DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < bsd_target_original_brk)\n",
|
||||
bsd_target_brk);
|
||||
return bsd_target_brk;
|
||||
}
|
||||
|
||||
/* If the new brk is less than the highest page reserved to the
|
||||
* target heap allocation, set it and we're almost done... */
|
||||
if (new_brk <= brk_page) {
|
||||
/* Heap contents are initialized to zero, as for anonymous
|
||||
* mapped pages. */
|
||||
if (new_brk > bsd_target_brk) {
|
||||
memset(g2h_untagged(bsd_target_brk), 0, new_brk - bsd_target_brk);
|
||||
}
|
||||
bsd_target_brk = new_brk;
|
||||
DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", bsd_target_brk);
|
||||
return bsd_target_brk;
|
||||
}
|
||||
|
||||
/* We need to allocate more memory after the brk... Note that
|
||||
* we don't use MAP_FIXED because that will map over the top of
|
||||
* any existing mapping (like the one with the host libc or qemu
|
||||
* itself); instead we treat "mapped but at wrong address" as
|
||||
* a failure and unmap again.
|
||||
*/
|
||||
new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
|
||||
mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
|
||||
PROT_READ|PROT_WRITE,
|
||||
MAP_ANON|MAP_PRIVATE, -1, 0));
|
||||
|
||||
if (mapped_addr == brk_page) {
|
||||
/* Heap contents are initialized to zero, as for anonymous
|
||||
* mapped pages. Technically the new pages are already
|
||||
* initialized to zero since they *are* anonymous mapped
|
||||
* pages, however we have to take care with the contents that
|
||||
* come from the remaining part of the previous page: it may
|
||||
* contains garbage data due to a previous heap usage (grown
|
||||
* then shrunken). */
|
||||
memset(g2h_untagged(bsd_target_brk), 0, brk_page - bsd_target_brk);
|
||||
|
||||
bsd_target_brk = new_brk;
|
||||
brk_page = HOST_PAGE_ALIGN(bsd_target_brk);
|
||||
DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
|
||||
bsd_target_brk);
|
||||
return bsd_target_brk;
|
||||
} else if (mapped_addr != -1) {
|
||||
/* Mapped but at wrong address, meaning there wasn't actually
|
||||
* enough space for this brk.
|
||||
*/
|
||||
target_munmap(mapped_addr, new_alloc_size);
|
||||
mapped_addr = -1;
|
||||
DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", bsd_target_brk);
|
||||
}
|
||||
else {
|
||||
DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", bsd_target_brk);
|
||||
}
|
||||
|
||||
/* For everything else, return the previous break. */
|
||||
return bsd_target_brk;
|
||||
}
|
||||
|
||||
/* shm_open(2) */
|
||||
static inline abi_long do_bsd_shm_open(abi_ulong arg1, abi_long arg2,
|
||||
abi_long arg3)
|
||||
{
|
||||
int ret;
|
||||
void *p;
|
||||
|
||||
#ifdef SHM_ANON
|
||||
#define SHM_PATH(p) (p) == SHM_ANON ? (p) : path(p)
|
||||
if (arg1 == (uintptr_t)SHM_ANON) {
|
||||
p = SHM_ANON;
|
||||
} else
|
||||
#else
|
||||
#define SHM_PATH(p) path(p)
|
||||
#endif
|
||||
{
|
||||
p = lock_user_string(arg1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
}
|
||||
ret = get_errno(shm_open(SHM_PATH(p),
|
||||
target_to_host_bitmask(arg2, fcntl_flags_tbl), arg3));
|
||||
|
||||
#ifdef SHM_ANON
|
||||
if (p != SHM_ANON)
|
||||
#endif
|
||||
{
|
||||
unlock_user(p, arg1, 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#undef SHM_PATH
|
||||
|
||||
/* shm_unlink(2) */
|
||||
static inline abi_long do_bsd_shm_unlink(abi_ulong arg1)
|
||||
{
|
||||
int ret;
|
||||
void *p;
|
||||
|
||||
p = lock_user_string(arg1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(shm_unlink(p)); /* XXX path(p)? */
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* shmget(2) */
|
||||
static inline abi_long do_bsd_shmget(abi_long arg1, abi_ulong arg2,
|
||||
abi_long arg3)
|
||||
{
|
||||
|
||||
return get_errno(shmget(arg1, arg2, arg3));
|
||||
}
|
||||
|
||||
/* shmctl(2) */
|
||||
static inline abi_long do_bsd_shmctl(abi_long shmid, abi_long cmd,
|
||||
abi_ulong buff)
|
||||
{
|
||||
struct shmid_ds dsarg;
|
||||
abi_long ret = -TARGET_EINVAL;
|
||||
|
||||
cmd &= 0xff;
|
||||
|
||||
switch (cmd) {
|
||||
case IPC_STAT:
|
||||
case IPC_SET:
|
||||
if (target_to_host_shmid_ds(&dsarg, buff)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(shmctl(shmid, cmd, &dsarg));
|
||||
if (host_to_target_shmid_ds(buff, &dsarg)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case IPC_RMID:
|
||||
ret = get_errno(shmctl(shmid, cmd, NULL));
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -TARGET_EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* shmat(2) */
|
||||
static inline abi_long do_bsd_shmat(int shmid, abi_ulong shmaddr, int shmflg)
|
||||
{
|
||||
abi_ulong raddr;
|
||||
abi_long ret;
|
||||
void *host_raddr;
|
||||
struct shmid_ds shm_info;
|
||||
int i;
|
||||
|
||||
/* Find out the length of the shared memory segment. */
|
||||
ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
|
||||
if (is_error(ret)) {
|
||||
/* Can't get the length */
|
||||
return ret;
|
||||
}
|
||||
|
||||
mmap_lock();
|
||||
|
||||
if (shmaddr) {
|
||||
host_raddr = shmat(shmid, (void *)g2h_untagged(shmaddr), shmflg);
|
||||
} else {
|
||||
abi_ulong mmap_start;
|
||||
|
||||
mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
|
||||
|
||||
if (mmap_start == -1) {
|
||||
errno = ENOMEM;
|
||||
host_raddr = (void *)-1;
|
||||
} else {
|
||||
host_raddr = shmat(shmid, g2h_untagged(mmap_start),
|
||||
shmflg /* | SHM_REMAP */);
|
||||
}
|
||||
}
|
||||
|
||||
if (host_raddr == (void *)-1) {
|
||||
mmap_unlock();
|
||||
return get_errno((long)host_raddr);
|
||||
}
|
||||
raddr = h2g((unsigned long)host_raddr);
|
||||
|
||||
page_set_flags(raddr, raddr + shm_info.shm_segsz,
|
||||
PAGE_VALID | PAGE_READ | ((shmflg & SHM_RDONLY) ? 0 : PAGE_WRITE));
|
||||
|
||||
for (i = 0; i < N_BSD_SHM_REGIONS; i++) {
|
||||
if (bsd_shm_regions[i].start == 0) {
|
||||
bsd_shm_regions[i].start = raddr;
|
||||
bsd_shm_regions[i].size = shm_info.shm_segsz;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mmap_unlock();
|
||||
return raddr;
|
||||
}
|
||||
|
||||
/* shmdt(2) */
|
||||
static inline abi_long do_bsd_shmdt(abi_ulong shmaddr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < N_BSD_SHM_REGIONS; ++i) {
|
||||
if (bsd_shm_regions[i].start == shmaddr) {
|
||||
bsd_shm_regions[i].start = 0;
|
||||
page_set_flags(shmaddr,
|
||||
shmaddr + bsd_shm_regions[i].size, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return get_errno(shmdt(g2h_untagged(shmaddr)));
|
||||
}
|
||||
|
||||
|
||||
static inline abi_long do_bsd_vadvise(void)
|
||||
{
|
||||
/* See sys_ovadvise() in vm_unix.c */
|
||||
qemu_log("qemu: Unsupported syscall vadvise()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
static inline abi_long do_bsd_sbrk(void)
|
||||
{
|
||||
/* see sys_sbrk() in vm_mmap.c */
|
||||
qemu_log("qemu: Unsupported syscall sbrk()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
static inline abi_long do_bsd_sstk(void)
|
||||
{
|
||||
/* see sys_sstk() in vm_mmap.c */
|
||||
qemu_log("qemu: Unsupported syscall sstk()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
#endif /* !_BSD_MMAN_H_ */
|
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
* BSD misc system call conversions routines
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
#include <sys/sem.h>
|
||||
#include <sys/uuid.h>
|
||||
|
||||
#include "qemu.h"
|
||||
#include "qemu-bsd.h"
|
||||
|
||||
/*
|
||||
* BSD uuidgen(2) struct uuid conversion
|
||||
*/
|
||||
abi_long host_to_target_uuid(abi_ulong target_addr, struct uuid *host_uuid)
|
||||
{
|
||||
struct target_uuid *target_uuid;
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_uuid, target_addr, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__put_user(host_uuid->time_low, &target_uuid->time_low);
|
||||
__put_user(host_uuid->time_mid, &target_uuid->time_mid);
|
||||
__put_user(host_uuid->time_hi_and_version,
|
||||
&target_uuid->time_hi_and_version);
|
||||
host_uuid->clock_seq_hi_and_reserved =
|
||||
target_uuid->clock_seq_hi_and_reserved;
|
||||
host_uuid->clock_seq_low = target_uuid->clock_seq_low;
|
||||
memcpy(host_uuid->node, target_uuid->node, TARGET_UUID_NODE_LEN);
|
||||
unlock_user_struct(target_uuid, target_addr, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long target_to_host_semarray(int semid, unsigned short **host_array,
|
||||
abi_ulong target_addr)
|
||||
{
|
||||
abi_long ret;
|
||||
int nsems, i;
|
||||
unsigned short *array;
|
||||
union semun semun;
|
||||
struct semid_ds semid_ds;
|
||||
|
||||
semun.buf = &semid_ds;
|
||||
ret = semctl(semid, 0, IPC_STAT, semun);
|
||||
if (ret == -1) {
|
||||
return get_errno(ret);
|
||||
}
|
||||
nsems = semid_ds.sem_nsems;
|
||||
*host_array = (unsigned short *)malloc(nsems * sizeof(unsigned short));
|
||||
array = lock_user(VERIFY_READ, target_addr,
|
||||
nsems*sizeof(unsigned short), 1);
|
||||
if (array == NULL) {
|
||||
free(*host_array);
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
for (i = 0; i < nsems; i++) {
|
||||
(*host_array)[i] = array[i];
|
||||
}
|
||||
unlock_user(array, target_addr, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
|
||||
unsigned short **host_array)
|
||||
{
|
||||
abi_long ret;
|
||||
int nsems, i;
|
||||
unsigned short *array;
|
||||
union semun semun;
|
||||
struct semid_ds semid_ds;
|
||||
|
||||
semun.buf = &semid_ds;
|
||||
|
||||
ret = semctl(semid, 0, IPC_STAT, semun);
|
||||
if (ret == -1) {
|
||||
free(*host_array);
|
||||
return get_errno(ret);
|
||||
}
|
||||
|
||||
nsems = semid_ds.sem_nsems;
|
||||
array = (unsigned short *)lock_user(VERIFY_WRITE, target_addr,
|
||||
nsems*sizeof(unsigned short), 0);
|
||||
if (array == NULL) {
|
||||
free(*host_array);
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
for (i = 0; i < nsems; i++) {
|
||||
array[i] = (*host_array)[i];
|
||||
}
|
||||
free(*host_array);
|
||||
unlock_user(array, target_addr, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
|
||||
abi_ulong target_addr)
|
||||
{
|
||||
struct target_semid_ds *target_sd;
|
||||
|
||||
if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if (target_to_host_ipc_perm(&(host_sd->sem_perm), (target_addr +
|
||||
offsetof(struct target_semid_ds, sem_perm)))) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
/* sem_base is not used by kernel for IPC_STAT/IPC_SET */
|
||||
/* host_sd->sem_base = g2h_untagged(target_sd->sem_base); */
|
||||
host_sd->sem_nsems = tswap16(target_sd->sem_nsems);
|
||||
#if defined(TARGET_I386)
|
||||
host_sd->sem_otime = tswap32(target_sd->sem_otime);
|
||||
host_sd->sem_ctime = tswap32(target_sd->sem_ctime);
|
||||
#else
|
||||
host_sd->sem_otime = tswap64(target_sd->sem_otime);
|
||||
host_sd->sem_ctime = tswap64(target_sd->sem_ctime);
|
||||
#endif
|
||||
unlock_user_struct(target_sd, target_addr, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long host_to_target_semid_ds(abi_ulong target_addr,
|
||||
struct semid_ds *host_sd)
|
||||
{
|
||||
struct target_semid_ds *target_sd;
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if (host_to_target_ipc_perm((target_addr +
|
||||
offsetof(struct target_semid_ds, sem_perm)),
|
||||
&(host_sd->sem_perm))) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
/* sem_base is not used by kernel for IPC_STAT/IPC_SET */
|
||||
/* target_sd->sem_base = h2g((void *)host_sd->sem_base); */
|
||||
target_sd->sem_nsems = tswap16(host_sd->sem_nsems);
|
||||
target_sd->sem_otime = tswapal(host_sd->sem_otime);
|
||||
target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
|
||||
unlock_user_struct(target_sd, target_addr, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
|
||||
abi_ulong target_addr)
|
||||
{
|
||||
struct target_msqid_ds *target_md;
|
||||
|
||||
if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
|
||||
memset(host_md, 0, sizeof(struct msqid_ds));
|
||||
if (target_to_host_ipc_perm(&(host_md->msg_perm), target_addr)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
|
||||
/* msg_first and msg_last are not used by IPC_SET/IPC_STAT in kernel. */
|
||||
host_md->msg_cbytes = tswapal(target_md->msg_cbytes);
|
||||
host_md->msg_qnum = tswapal(target_md->msg_qnum);
|
||||
host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
|
||||
host_md->msg_lspid = tswapal(target_md->msg_lspid);
|
||||
host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
|
||||
#if defined(TARGET_I386)
|
||||
host_md->msg_stime = tswap32(target_md->msg_stime);
|
||||
host_md->msg_rtime = tswap32(target_md->msg_rtime);
|
||||
host_md->msg_ctime = tswap32(target_md->msg_ctime);
|
||||
#else
|
||||
host_md->msg_stime = tswap64(target_md->msg_stime);
|
||||
host_md->msg_rtime = tswap64(target_md->msg_rtime);
|
||||
host_md->msg_ctime = tswap64(target_md->msg_ctime);
|
||||
#endif
|
||||
unlock_user_struct(target_md, target_addr, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long host_to_target_msqid_ds(abi_ulong target_addr,
|
||||
struct msqid_ds *host_md)
|
||||
{
|
||||
struct target_msqid_ds *target_md;
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
|
||||
memset(target_md, 0, sizeof(struct target_msqid_ds));
|
||||
if (host_to_target_ipc_perm(target_addr, &(host_md->msg_perm))) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
|
||||
/* msg_first and msg_last are not used by IPC_SET/IPC_STAT in kernel. */
|
||||
target_md->msg_cbytes = tswapal(host_md->msg_cbytes);
|
||||
target_md->msg_qnum = tswapal(host_md->msg_qnum);
|
||||
target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
|
||||
target_md->msg_lspid = tswapal(host_md->msg_lspid);
|
||||
target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
|
||||
#if defined(TARGET_I386)
|
||||
target_md->msg_stime = tswap32(host_md->msg_stime);
|
||||
target_md->msg_rtime = tswap32(host_md->msg_rtime);
|
||||
target_md->msg_ctime = tswap32(host_md->msg_ctime);
|
||||
#else
|
||||
target_md->msg_stime = tswap64(host_md->msg_stime);
|
||||
target_md->msg_rtime = tswap64(host_md->msg_rtime);
|
||||
target_md->msg_ctime = tswap64(host_md->msg_ctime);
|
||||
#endif
|
||||
unlock_user_struct(target_md, target_addr, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,388 @@
|
|||
/*
|
||||
* miscellaneous BSD system call shims
|
||||
*
|
||||
* 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_MISC_H_
|
||||
#define __BSD_MISC_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
#include <sys/sem.h>
|
||||
#include <sys/uuid.h>
|
||||
|
||||
#include "qemu-bsd.h"
|
||||
|
||||
#ifdef MSGMAX
|
||||
static int bsd_msgmax = MSGMAX;
|
||||
#else
|
||||
#if !defined(__FreeBSD__)
|
||||
#error Unsure how to proceed, no MSGMAX
|
||||
#endif
|
||||
|
||||
static int bsd_msgmax;
|
||||
#endif
|
||||
|
||||
/* quotactl(2) */
|
||||
static inline abi_long do_bsd_quotactl(abi_ulong path, abi_long cmd,
|
||||
__unused abi_ulong target_addr)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall quotactl()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* reboot(2) */
|
||||
static inline abi_long do_bsd_reboot(abi_long how)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall reboot()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* uuidgen(2) */
|
||||
static inline abi_long do_bsd_uuidgen(abi_ulong target_addr, int count)
|
||||
{
|
||||
int i;
|
||||
abi_long ret;
|
||||
struct uuid *host_uuid;
|
||||
|
||||
if (count < 1 || count > 2048) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
|
||||
host_uuid = (struct uuid *)g_malloc(count * sizeof(struct uuid));
|
||||
|
||||
if (host_uuid == NULL) {
|
||||
return -TARGET_ENOMEM;
|
||||
}
|
||||
|
||||
ret = get_errno(uuidgen(host_uuid, count));
|
||||
if (is_error(ret)) {
|
||||
goto out;
|
||||
}
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = host_to_target_uuid(target_addr +
|
||||
(abi_ulong)(sizeof(struct target_uuid) * i), &host_uuid[i]);
|
||||
if (is_error(ret)) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
g_free(host_uuid);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* System V Semaphores
|
||||
*/
|
||||
|
||||
/* semget(2) */
|
||||
static inline abi_long do_bsd_semget(abi_long key, int nsems,
|
||||
int target_flags)
|
||||
{
|
||||
|
||||
return get_errno(semget(key, nsems,
|
||||
target_to_host_bitmask(target_flags, ipc_flags_tbl)));
|
||||
}
|
||||
|
||||
/* semop(2) */
|
||||
static inline abi_long do_bsd_semop(int semid, abi_long ptr, unsigned nsops)
|
||||
{
|
||||
struct sembuf sops[nsops];
|
||||
struct target_sembuf *target_sembuf;
|
||||
int i;
|
||||
|
||||
target_sembuf = lock_user(VERIFY_READ, ptr,
|
||||
nsops * sizeof(struct target_sembuf), 1);
|
||||
if (target_sembuf == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
for (i = 0; i < nsops; i++) {
|
||||
__get_user(sops[i].sem_num, &target_sembuf[i].sem_num);
|
||||
__get_user(sops[i].sem_op, &target_sembuf[i].sem_op);
|
||||
__get_user(sops[i].sem_flg, &target_sembuf[i].sem_flg);
|
||||
}
|
||||
unlock_user(target_sembuf, ptr, 0);
|
||||
|
||||
return semop(semid, sops, nsops);
|
||||
}
|
||||
|
||||
/* __semctl(2) */
|
||||
static inline abi_long do_bsd___semctl(int semid, int semnum, int target_cmd,
|
||||
union target_semun target_su)
|
||||
{
|
||||
union semun arg;
|
||||
struct semid_ds dsarg;
|
||||
unsigned short *array = NULL;
|
||||
int host_cmd;
|
||||
abi_long ret = 0;
|
||||
abi_long err;
|
||||
|
||||
switch (target_cmd) {
|
||||
case TARGET_GETVAL:
|
||||
host_cmd = GETVAL;
|
||||
break;
|
||||
|
||||
case TARGET_SETVAL:
|
||||
host_cmd = SETVAL;
|
||||
break;
|
||||
|
||||
case TARGET_GETALL:
|
||||
host_cmd = GETALL;
|
||||
break;
|
||||
|
||||
case TARGET_SETALL:
|
||||
host_cmd = SETALL;
|
||||
break;
|
||||
|
||||
case TARGET_IPC_STAT:
|
||||
host_cmd = IPC_STAT;
|
||||
break;
|
||||
|
||||
case TARGET_IPC_SET:
|
||||
host_cmd = IPC_SET;
|
||||
break;
|
||||
|
||||
case TARGET_IPC_RMID:
|
||||
host_cmd = IPC_RMID;
|
||||
break;
|
||||
|
||||
case TARGET_GETPID:
|
||||
host_cmd = GETPID;
|
||||
break;
|
||||
|
||||
case TARGET_GETNCNT:
|
||||
host_cmd = GETNCNT;
|
||||
break;
|
||||
|
||||
case TARGET_GETZCNT:
|
||||
host_cmd = GETZCNT;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
|
||||
switch (host_cmd) {
|
||||
case GETVAL:
|
||||
case SETVAL:
|
||||
/* In 64 bit cross-endian situations, we will erroneously pick up
|
||||
* the wrong half of the union for the "val" element. To rectify
|
||||
* this, the entire 8-byte structure is byteswapped, followed by
|
||||
* a swap of the 4 byte val field. In other cases, the data is
|
||||
* already in proper host byte order. */
|
||||
if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
|
||||
target_su.buf = tswapal(target_su.buf);
|
||||
arg.val = tswap32(target_su.val);
|
||||
} else {
|
||||
arg.val = target_su.val;
|
||||
}
|
||||
ret = get_errno(semctl(semid, semnum, host_cmd, arg));
|
||||
break;
|
||||
|
||||
case GETALL:
|
||||
case SETALL:
|
||||
err = target_to_host_semarray(semid, &array, target_su.array);
|
||||
if (is_error(err)) {
|
||||
return err;
|
||||
}
|
||||
arg.array = array;
|
||||
ret = get_errno(semctl(semid, semnum, host_cmd, arg));
|
||||
err = host_to_target_semarray(semid, target_su.array, &array);
|
||||
if (is_error(err)) {
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
|
||||
case IPC_STAT:
|
||||
case IPC_SET:
|
||||
err = target_to_host_semid_ds(&dsarg, target_su.buf);
|
||||
if (is_error(err)) {
|
||||
return err;
|
||||
}
|
||||
arg.buf = &dsarg;
|
||||
ret = get_errno(semctl(semid, semnum, host_cmd, arg));
|
||||
err = host_to_target_semid_ds(target_su.buf, &dsarg);
|
||||
if (is_error(err)) {
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
|
||||
case IPC_RMID:
|
||||
case GETPID:
|
||||
case GETNCNT:
|
||||
case GETZCNT:
|
||||
ret = get_errno(semctl(semid, semnum, host_cmd, NULL));
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -TARGET_EINVAL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* msgctl(2) */
|
||||
static inline abi_long do_bsd_msgctl(int msgid, int target_cmd, abi_long ptr)
|
||||
{
|
||||
struct msqid_ds dsarg;
|
||||
abi_long ret = -TARGET_EINVAL;
|
||||
int host_cmd;
|
||||
|
||||
switch (target_cmd) {
|
||||
case TARGET_IPC_STAT:
|
||||
host_cmd = IPC_STAT;
|
||||
break;
|
||||
|
||||
case TARGET_IPC_SET:
|
||||
host_cmd = IPC_SET;
|
||||
break;
|
||||
|
||||
case TARGET_IPC_RMID:
|
||||
host_cmd = IPC_RMID;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
|
||||
switch (host_cmd) {
|
||||
case IPC_STAT:
|
||||
case IPC_SET:
|
||||
if (target_to_host_msqid_ds(&dsarg, ptr)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(msgctl(msgid, host_cmd, &dsarg));
|
||||
if (host_to_target_msqid_ds(ptr, &dsarg)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case IPC_RMID:
|
||||
ret = get_errno(msgctl(msgid, host_cmd, NULL));
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -TARGET_EINVAL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct kern_mymsg {
|
||||
long mtype;
|
||||
char mtext[1];
|
||||
};
|
||||
|
||||
static inline abi_long bsd_validate_msgsz(abi_ulong msgsz)
|
||||
{
|
||||
|
||||
/* Fetch msgmax the first time we need it. */
|
||||
if (bsd_msgmax == 0) {
|
||||
size_t len = sizeof(bsd_msgmax);
|
||||
|
||||
if (sysctlbyname("kern.ipc.msgmax", &bsd_msgmax, &len, NULL, 0) == -1)
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
|
||||
if (msgsz > bsd_msgmax)
|
||||
return -TARGET_EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* msgsnd(2) */
|
||||
static inline abi_long do_bsd_msgsnd(int msqid, abi_long msgp,
|
||||
abi_ulong msgsz, int msgflg)
|
||||
{
|
||||
struct target_msgbuf *target_mb;
|
||||
struct kern_mymsg *host_mb;
|
||||
abi_long ret;
|
||||
|
||||
ret = bsd_validate_msgsz(msgsz);
|
||||
if (is_error(ret))
|
||||
return ret;
|
||||
if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
host_mb = g_malloc(msgsz+sizeof(long));
|
||||
host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
|
||||
memcpy(host_mb->mtext, target_mb->mtext, msgsz);
|
||||
ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
|
||||
g_free(host_mb);
|
||||
unlock_user_struct(target_mb, msgp, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* msgget(2) */
|
||||
static inline abi_long do_bsd_msgget(abi_long key, abi_long msgflag)
|
||||
{
|
||||
abi_long ret;
|
||||
|
||||
ret = get_errno(msgget(key, msgflag));
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* msgrcv(2) */
|
||||
static inline abi_long do_bsd_msgrcv(int msqid, abi_long msgp,
|
||||
abi_ulong msgsz, abi_long msgtyp, int msgflg)
|
||||
{
|
||||
struct target_msgbuf *target_mb = NULL;
|
||||
char *target_mtext;
|
||||
struct kern_mymsg *host_mb;
|
||||
abi_long ret = 0;
|
||||
|
||||
ret = bsd_validate_msgsz(msgsz);
|
||||
if (is_error(ret))
|
||||
return ret;
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
host_mb = g_malloc(msgsz+sizeof(long));
|
||||
ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapal(msgtyp), msgflg));
|
||||
if (ret > 0) {
|
||||
abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
|
||||
target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
|
||||
if (target_mtext == NULL) {
|
||||
ret = -TARGET_EFAULT;
|
||||
goto end;
|
||||
}
|
||||
memcpy(target_mb->mtext, host_mb->mtext, ret);
|
||||
unlock_user(target_mtext, target_mtext_addr, ret);
|
||||
}
|
||||
if (!is_error(ret))
|
||||
target_mb->mtype = tswapal(host_mb->mtype);
|
||||
end:
|
||||
if (target_mb != NULL) {
|
||||
unlock_user_struct(target_mb, msgp, 1);
|
||||
}
|
||||
g_free(host_mb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* getdtablesize(2) */
|
||||
static inline abi_long do_bsd_getdtablesize(void)
|
||||
{
|
||||
|
||||
return get_errno(getdtablesize());
|
||||
}
|
||||
|
||||
#endif /* ! __BSD_MISC_H_ */
|
|
@ -0,0 +1,121 @@
|
|||
/*-
|
||||
* Copyright (c) 1982, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)mman.h 8.2 (Berkeley) 1/9/95
|
||||
* $FreeBSD: src/sys/sys/mman.h,v 1.42 2008/03/28 04:29:27 ps Exp $
|
||||
*/
|
||||
|
||||
#define TARGET_FREEBSD_MAP_RESERVED0080 0x0080 /* previously misimplemented MAP_INHERIT */
|
||||
#define TARGET_FREEBSD_MAP_RESERVED0100 0x0100 /* previously unimplemented MAP_NOEXTEND */
|
||||
#define TARGET_FREEBSD_MAP_STACK 0x0400 /* region grows down, like a stack */
|
||||
#define TARGET_FREEBSD_MAP_NOSYNC 0x0800 /* page to but do not sync underlying file */
|
||||
|
||||
#define TARGET_FREEBSD_MAP_FLAGMASK 0x1ff7
|
||||
|
||||
/* $NetBSD: mman.h,v 1.42 2008/11/18 22:13:49 ad Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)mman.h 8.2 (Berkeley) 1/9/95
|
||||
*/
|
||||
#define TARGET_NETBSD_MAP_INHERIT 0x0080 /* region is retained after exec */
|
||||
#define TARGET_NETBSD_MAP_TRYFIXED 0x0400 /* attempt hint address, even within break */
|
||||
#define TARGET_NETBSD_MAP_WIRED 0x0800 /* mlock() mapping when it is established */
|
||||
|
||||
#define TARGET_NETBSD_MAP_STACK 0x2000 /* allocated from memory, swap space (stack) */
|
||||
|
||||
#define TARGET_NETBSD_MAP_FLAGMASK 0x3ff7
|
||||
|
||||
/* $OpenBSD: mman.h,v 1.18 2003/07/21 22:52:19 tedu Exp $ */
|
||||
/* $NetBSD: mman.h,v 1.11 1995/03/26 20:24:23 jtc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)mman.h 8.1 (Berkeley) 6/2/93
|
||||
*/
|
||||
|
||||
#define TARGET_OPENBSD_MAP_INHERIT 0x0080 /* region is retained after exec */
|
||||
#define TARGET_OPENBSD_MAP_NOEXTEND 0x0100 /* for MAP_FILE, don't change file size */
|
||||
#define TARGET_OPENBSD_MAP_TRYFIXED 0x0400 /* attempt hint address, even within heap */
|
||||
|
||||
#define TARGET_OPENBSD_MAP_FLAGMASK 0x17f7
|
||||
|
||||
// XXX
|
||||
#define TARGET_BSD_MAP_FLAGMASK 0x3ff7
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* BSD process related system call helpers
|
||||
*
|
||||
* Copyright (c) 2013-14 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/>.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/cpuset.h>
|
||||
#endif
|
||||
#include <sys/resource.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "qemu.h"
|
||||
#include "qemu-bsd.h"
|
||||
|
||||
#include "bsd-proc.h"
|
||||
|
||||
/*
|
||||
* resource/rusage conversion
|
||||
*/
|
||||
int target_to_host_resource(int code)
|
||||
{
|
||||
|
||||
switch (code) {
|
||||
case TARGET_RLIMIT_AS:
|
||||
return RLIMIT_AS;
|
||||
|
||||
case TARGET_RLIMIT_CORE:
|
||||
return RLIMIT_CORE;
|
||||
|
||||
case TARGET_RLIMIT_CPU:
|
||||
return RLIMIT_CPU;
|
||||
|
||||
case TARGET_RLIMIT_DATA:
|
||||
return RLIMIT_DATA;
|
||||
|
||||
case TARGET_RLIMIT_FSIZE:
|
||||
return RLIMIT_FSIZE;
|
||||
|
||||
case TARGET_RLIMIT_MEMLOCK:
|
||||
return RLIMIT_MEMLOCK;
|
||||
|
||||
case TARGET_RLIMIT_NOFILE:
|
||||
return RLIMIT_NOFILE;
|
||||
|
||||
case TARGET_RLIMIT_NPROC:
|
||||
return RLIMIT_NPROC;
|
||||
|
||||
case TARGET_RLIMIT_RSS:
|
||||
return RLIMIT_RSS;
|
||||
|
||||
case TARGET_RLIMIT_SBSIZE:
|
||||
return RLIMIT_SBSIZE;
|
||||
|
||||
case TARGET_RLIMIT_STACK:
|
||||
return RLIMIT_STACK;
|
||||
|
||||
case TARGET_RLIMIT_SWAP:
|
||||
return RLIMIT_SWAP;
|
||||
|
||||
case TARGET_RLIMIT_NPTS:
|
||||
return RLIMIT_NPTS;
|
||||
|
||||
default:
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
rlim_t target_to_host_rlim(abi_llong target_rlim)
|
||||
{
|
||||
abi_llong target_rlim_swap;
|
||||
rlim_t result;
|
||||
|
||||
target_rlim_swap = tswap64(target_rlim);
|
||||
if (target_rlim_swap == TARGET_RLIM_INFINITY) {
|
||||
return RLIM_INFINITY;
|
||||
}
|
||||
|
||||
result = target_rlim_swap;
|
||||
if (target_rlim_swap != (rlim_t)result) {
|
||||
return RLIM_INFINITY;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
abi_llong host_to_target_rlim(rlim_t rlim)
|
||||
{
|
||||
abi_llong target_rlim_swap;
|
||||
abi_llong result;
|
||||
|
||||
if (rlim == RLIM_INFINITY || rlim != (abi_llong)rlim) {
|
||||
target_rlim_swap = TARGET_RLIM_INFINITY;
|
||||
} else {
|
||||
target_rlim_swap = rlim;
|
||||
}
|
||||
result = tswap64(target_rlim_swap);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void h2t_rusage(const struct rusage *rusage,
|
||||
struct target_freebsd_rusage *target_rusage)
|
||||
{
|
||||
__put_user(rusage->ru_utime.tv_sec, &target_rusage->ru_utime.tv_sec);
|
||||
__put_user(rusage->ru_utime.tv_usec, &target_rusage->ru_utime.tv_usec);
|
||||
|
||||
__put_user(rusage->ru_stime.tv_sec, &target_rusage->ru_stime.tv_sec);
|
||||
__put_user(rusage->ru_stime.tv_usec, &target_rusage->ru_stime.tv_usec);
|
||||
|
||||
__put_user(rusage->ru_maxrss, &target_rusage->ru_maxrss);
|
||||
__put_user(rusage->ru_idrss, &target_rusage->ru_idrss);
|
||||
__put_user(rusage->ru_idrss, &target_rusage->ru_idrss);
|
||||
__put_user(rusage->ru_isrss, &target_rusage->ru_isrss);
|
||||
__put_user(rusage->ru_minflt, &target_rusage->ru_minflt);
|
||||
__put_user(rusage->ru_majflt, &target_rusage->ru_majflt);
|
||||
__put_user(rusage->ru_nswap, &target_rusage->ru_nswap);
|
||||
__put_user(rusage->ru_inblock, &target_rusage->ru_inblock);
|
||||
__put_user(rusage->ru_oublock, &target_rusage->ru_oublock);
|
||||
__put_user(rusage->ru_msgsnd, &target_rusage->ru_msgsnd);
|
||||
__put_user(rusage->ru_msgrcv, &target_rusage->ru_msgrcv);
|
||||
__put_user(rusage->ru_nsignals, &target_rusage->ru_nsignals);
|
||||
__put_user(rusage->ru_nvcsw, &target_rusage->ru_nvcsw);
|
||||
__put_user(rusage->ru_nivcsw, &target_rusage->ru_nivcsw);
|
||||
}
|
||||
|
||||
abi_long host_to_target_rusage(abi_ulong target_addr,
|
||||
const struct rusage *rusage)
|
||||
{
|
||||
struct target_freebsd_rusage *target_rusage;
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
h2t_rusage(rusage, target_rusage);
|
||||
unlock_user_struct(target_rusage, target_addr, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 1000000
|
||||
abi_long host_to_target_wrusage(abi_ulong target_addr,
|
||||
const struct __wrusage *wrusage)
|
||||
{
|
||||
struct target_freebsd__wrusage *target_wrusage;
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_wrusage, target_addr, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
h2t_rusage(&wrusage->wru_self, &target_wrusage->wru_self);
|
||||
h2t_rusage(&wrusage->wru_children, &target_wrusage->wru_children);
|
||||
unlock_user_struct(target_wrusage, target_addr, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* __FreeBSD_version >= 1000000 */
|
||||
|
||||
/*
|
||||
* wait status conversion.
|
||||
*
|
||||
* Map host to target signal numbers for the wait family of syscalls.
|
||||
* Assume all other status bits are the same.
|
||||
*/
|
||||
int host_to_target_waitstatus(int status)
|
||||
{
|
||||
if (WIFSIGNALED(status)) {
|
||||
return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
|
||||
}
|
||||
if (WIFSTOPPED(status)) {
|
||||
return (host_to_target_signal(WSTOPSIG(status)) << 8) | (status & 0xff);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int
|
||||
bsd_get_ncpu(void)
|
||||
{
|
||||
static int ncpu = -1;
|
||||
|
||||
if (ncpu != -1)
|
||||
return (ncpu);
|
||||
#ifdef __FreeBSD__
|
||||
if (ncpu == -1) {
|
||||
cpuset_t mask;
|
||||
|
||||
CPU_ZERO(&mask);
|
||||
|
||||
if (cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(mask),
|
||||
&mask) == 0)
|
||||
ncpu = CPU_COUNT(&mask);
|
||||
}
|
||||
#endif
|
||||
#ifdef _SC_NPROCESSORS_ONLN
|
||||
if (ncpu == -1)
|
||||
ncpu = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
#endif
|
||||
#if defined(CTL_HW) && defined(HW_NCPU)
|
||||
if (ncpu == -1) {
|
||||
int mib[2] = {CTL_HW, HW_NCPU};
|
||||
size_t sz;
|
||||
|
||||
sz = sizeof(ncpu);
|
||||
if (sysctl(mib, 2, &ncpu, &sz, NULL, NULL) == -1)
|
||||
ncpu = -1;
|
||||
}
|
||||
#endif
|
||||
if (ncpu == -1) {
|
||||
gemu_log("XXX Missing bsd_get_ncpu() implementation\n");
|
||||
ncpu = 1;
|
||||
}
|
||||
return (ncpu);
|
||||
}
|
||||
|
|
@ -0,0 +1,476 @@
|
|||
/*
|
||||
* process related system call shims and definitions
|
||||
*
|
||||
* Copyright (c) 2013-14 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_PROC_H_
|
||||
#define __BSD_PROC_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "qemu-bsd.h"
|
||||
|
||||
extern int _getlogin(char*, int);
|
||||
|
||||
/* exit(2) */
|
||||
static inline abi_long do_bsd_exit(void *cpu_env, abi_long arg1)
|
||||
{
|
||||
#ifdef TARGET_GPROF
|
||||
_mcleanup();
|
||||
#endif
|
||||
gdb_exit(arg1);
|
||||
qemu_plugin_user_exit();
|
||||
/* XXX: should free thread stack and CPU env here */
|
||||
_exit(arg1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* getgroups(2) */
|
||||
static inline abi_long do_bsd_getgroups(abi_long gidsetsize, abi_long arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
uint32_t *target_grouplist;
|
||||
gid_t *grouplist;
|
||||
int i;
|
||||
|
||||
grouplist = alloca(gidsetsize * sizeof(gid_t));
|
||||
ret = get_errno(getgroups(gidsetsize, grouplist));
|
||||
if (gidsetsize != 0) {
|
||||
if (!is_error(ret)) {
|
||||
target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0);
|
||||
if (!target_grouplist) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
for (i = 0; i < ret; i++) {
|
||||
target_grouplist[i] = tswap32(grouplist[i]);
|
||||
}
|
||||
unlock_user(target_grouplist, arg2, gidsetsize * 2);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* setgroups(2) */
|
||||
static inline abi_long do_bsd_setgroups(abi_long gidsetsize, abi_long arg2)
|
||||
{
|
||||
uint32_t *target_grouplist;
|
||||
gid_t *grouplist;
|
||||
int i;
|
||||
|
||||
grouplist = alloca(gidsetsize * sizeof(gid_t));
|
||||
target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1);
|
||||
if (!target_grouplist) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
for (i = 0; i < gidsetsize; i++) {
|
||||
grouplist[i] = tswap32(target_grouplist[i]);
|
||||
}
|
||||
unlock_user(target_grouplist, arg2, 0);
|
||||
return get_errno(setgroups(gidsetsize, grouplist));
|
||||
}
|
||||
|
||||
/* umask(2) */
|
||||
static inline abi_long do_bsd_umask(abi_long arg1)
|
||||
{
|
||||
|
||||
return get_errno(umask(arg1));
|
||||
}
|
||||
|
||||
/* setlogin(2) */
|
||||
static inline abi_long do_bsd_setlogin(abi_long arg1)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
|
||||
p = lock_user_string(arg1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(setlogin(p));
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* getlogin(2) */
|
||||
static inline abi_long do_bsd_getlogin(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
|
||||
p = lock_user_string(arg1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(_getlogin(p, arg2));
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* getrusage(2) */
|
||||
static inline abi_long do_bsd_getrusage(abi_long who, abi_ulong target_addr)
|
||||
{
|
||||
abi_long ret;
|
||||
struct rusage rusage;
|
||||
|
||||
ret = get_errno(getrusage(who, &rusage));
|
||||
if (!is_error(ret)) {
|
||||
host_to_target_rusage(target_addr, &rusage);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* getrlimit(2) */
|
||||
static inline abi_long do_bsd_getrlimit(abi_long arg1, abi_ulong arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
int resource = target_to_host_resource(arg1);
|
||||
struct target_rlimit *target_rlim;
|
||||
struct rlimit rlim;
|
||||
|
||||
switch (resource) {
|
||||
case RLIMIT_STACK:
|
||||
rlim.rlim_cur = target_dflssiz;
|
||||
rlim.rlim_max = target_maxssiz;
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
case RLIMIT_DATA:
|
||||
rlim.rlim_cur = target_dfldsiz;
|
||||
rlim.rlim_max = target_maxdsiz;
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = get_errno(getrlimit(resource, &rlim));
|
||||
break;
|
||||
}
|
||||
if (!is_error(ret)) {
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
|
||||
target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
|
||||
unlock_user_struct(target_rlim, arg2, 1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* setrlimit(2) */
|
||||
static inline abi_long do_bsd_setrlimit(abi_long arg1, abi_ulong arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
int resource = target_to_host_resource(arg1);
|
||||
struct target_rlimit *target_rlim;
|
||||
struct rlimit rlim;
|
||||
|
||||
if (RLIMIT_STACK == resource) {
|
||||
/* XXX We should, maybe, allow the stack size to shrink */
|
||||
ret = -TARGET_EPERM;
|
||||
} else {
|
||||
if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
|
||||
rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
|
||||
unlock_user_struct(target_rlim, arg2, 0);
|
||||
ret = get_errno(setrlimit(resource, &rlim));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* getpid(2) */
|
||||
static inline abi_long do_bsd_getpid(void)
|
||||
{
|
||||
|
||||
return get_errno(getpid());
|
||||
}
|
||||
|
||||
/* getppid(2) */
|
||||
static inline abi_long do_bsd_getppid(void)
|
||||
{
|
||||
|
||||
return get_errno(getppid());
|
||||
}
|
||||
|
||||
/* getuid(2) */
|
||||
static inline abi_long do_bsd_getuid(void)
|
||||
{
|
||||
|
||||
return get_errno(getuid());
|
||||
}
|
||||
|
||||
/* geteuid(2) */
|
||||
static inline abi_long do_bsd_geteuid(void)
|
||||
{
|
||||
|
||||
return get_errno(geteuid());
|
||||
}
|
||||
|
||||
/* getgid(2) */
|
||||
static inline abi_long do_bsd_getgid(void)
|
||||
{
|
||||
|
||||
return get_errno(getgid());
|
||||
}
|
||||
|
||||
/* getegid(2) */
|
||||
static inline abi_long do_bsd_getegid(void)
|
||||
{
|
||||
|
||||
return get_errno(getegid());
|
||||
}
|
||||
|
||||
/* setuid(2) */
|
||||
static inline abi_long do_bsd_setuid(abi_long arg1)
|
||||
{
|
||||
|
||||
return get_errno(setuid(arg1));
|
||||
}
|
||||
|
||||
/* seteuid(2) */
|
||||
static inline abi_long do_bsd_seteuid(abi_long arg1)
|
||||
{
|
||||
|
||||
return get_errno(seteuid(arg1));
|
||||
}
|
||||
|
||||
/* setgid(2) */
|
||||
static inline abi_long do_bsd_setgid(abi_long arg1)
|
||||
{
|
||||
|
||||
return get_errno(setgid(arg1));
|
||||
}
|
||||
|
||||
/* setegid(2) */
|
||||
static inline abi_long do_bsd_setegid(abi_long arg1)
|
||||
{
|
||||
|
||||
return get_errno(setegid(arg1));
|
||||
}
|
||||
|
||||
/* getpgid(2) */
|
||||
static inline abi_long do_bsd_getpgid(pid_t pid)
|
||||
{
|
||||
|
||||
return get_errno(getpgid(pid));
|
||||
}
|
||||
|
||||
/* setpgid(2) */
|
||||
static inline abi_long do_bsd_setpgid(int pid, int pgrp)
|
||||
{
|
||||
|
||||
return get_errno(setpgid(pid, pgrp));
|
||||
}
|
||||
|
||||
/* getpgrp(2) */
|
||||
static inline abi_long do_bsd_getpgrp(void)
|
||||
{
|
||||
|
||||
return get_errno(getpgrp());
|
||||
}
|
||||
|
||||
/* setreuid(2) */
|
||||
static inline abi_long do_bsd_setreuid(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
|
||||
return get_errno(setreuid(arg1, arg2));
|
||||
}
|
||||
|
||||
/* setregid(2) */
|
||||
static inline abi_long do_bsd_setregid(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
|
||||
return get_errno(setregid(arg1, arg2));
|
||||
}
|
||||
|
||||
/* setresgid(2) */
|
||||
static inline abi_long do_bsd_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
|
||||
{
|
||||
|
||||
return get_errno(setresgid(rgid, egid, sgid));
|
||||
}
|
||||
|
||||
/* setresuid(2) */
|
||||
static inline abi_long do_bsd_setresuid(uid_t ruid, uid_t euid, uid_t suid)
|
||||
{
|
||||
|
||||
return get_errno(setresuid(ruid, euid, suid));
|
||||
}
|
||||
|
||||
/* getresuid(2) */
|
||||
static inline abi_long do_bsd_getresuid(abi_ulong arg1, abi_ulong arg2,
|
||||
abi_ulong arg3)
|
||||
{
|
||||
abi_long ret;
|
||||
uid_t ruid, euid, suid;
|
||||
|
||||
ret = get_errno(getresuid(&ruid, &euid, &suid));
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
if (put_user_s32(ruid, arg1)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if (put_user_s32(euid, arg2)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if (put_user_s32(suid, arg3)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* getresgid(2) */
|
||||
static inline abi_long do_bsd_getresgid(abi_ulong arg1, abi_ulong arg2,
|
||||
abi_ulong arg3)
|
||||
{
|
||||
abi_long ret;
|
||||
uid_t ruid, euid, suid;
|
||||
|
||||
ret = get_errno(getresgid(&ruid, &euid, &suid));
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
if (put_user_s32(ruid, arg1)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if (put_user_s32(euid, arg2)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if (put_user_s32(suid, arg3)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* getsid(2) */
|
||||
static inline abi_long do_bsd_getsid(abi_long arg1)
|
||||
{
|
||||
|
||||
return get_errno(getsid(arg1));
|
||||
}
|
||||
|
||||
/* setsid(2) */
|
||||
static inline abi_long do_bsd_setsid(void)
|
||||
{
|
||||
|
||||
return get_errno(setsid());
|
||||
}
|
||||
|
||||
/* issetugid(2) */
|
||||
static inline abi_long do_bsd_issetugid(void)
|
||||
{
|
||||
|
||||
return get_errno(issetugid());
|
||||
}
|
||||
|
||||
/* profil(2) */
|
||||
static inline abi_long do_bsd_profil(abi_long arg1, abi_long arg2,
|
||||
abi_long arg3, abi_long arg4)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall profil()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
|
||||
/* ktrace(2) */
|
||||
static inline abi_long do_bsd_ktrace(abi_long arg1, abi_long arg2,
|
||||
abi_long arg3, abi_long arg4)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall ktrace()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* utrace(2) */
|
||||
static inline abi_long do_bsd_utrace(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall ptrace()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
|
||||
/* ptrace(2) */
|
||||
static inline abi_long do_bsd_ptrace(abi_long arg1, abi_long arg2,
|
||||
abi_long arg3, abi_long arg4)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall ptrace()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* getpriority(2) */
|
||||
static inline abi_long do_bsd_getpriority(abi_long which, abi_long who)
|
||||
{
|
||||
abi_long ret;
|
||||
/*
|
||||
* Note that negative values are valid for getpriority, so we must
|
||||
* differentiate based on errno settings.
|
||||
*/
|
||||
errno = 0;
|
||||
ret = getpriority(which, who);
|
||||
if (ret == -1 && errno != 0) {
|
||||
ret = -host_to_target_errno(errno);
|
||||
return ret;
|
||||
}
|
||||
/* Return value is a biased priority to avoid negative numbers. */
|
||||
ret = 20 - ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* setpriority(2) */
|
||||
static inline abi_long do_bsd_setpriority(abi_long which, abi_long who,
|
||||
abi_long prio)
|
||||
{
|
||||
|
||||
return get_errno(setpriority(which, who, prio));
|
||||
}
|
||||
|
||||
/* sched_yield(2) */
|
||||
static inline abi_long do_bsd_sched_yield(void)
|
||||
{
|
||||
|
||||
return get_errno(sched_yield());
|
||||
}
|
||||
|
||||
/* sched_get_priority_min(2) */
|
||||
static inline abi_long do_bsd_sched_get_priority_min(int policy)
|
||||
{
|
||||
|
||||
return get_errno(sched_get_priority_min(policy));
|
||||
}
|
||||
|
||||
/* sched_get_priority_max(2) */
|
||||
static inline abi_long do_bsd_sched_get_priority_max(int policy)
|
||||
{
|
||||
|
||||
return get_errno(sched_get_priority_max(policy));
|
||||
}
|
||||
|
||||
int bsd_get_ncpu(void);
|
||||
|
||||
#endif /* !__BSD_PROC_H_ */
|
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
* signal related system call shims
|
||||
*
|
||||
* 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_SIGNAL_H_
|
||||
#define __BSD_SIGNAL_H_
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
/* sigaction(2) */
|
||||
static inline abi_long do_bsd_sigaction(abi_long arg1, abi_long arg2,
|
||||
abi_long arg3)
|
||||
{
|
||||
abi_long ret;
|
||||
struct target_sigaction *old_act, act, oact, *pact;
|
||||
|
||||
if (arg2) {
|
||||
if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
act._sa_handler = old_act->_sa_handler;
|
||||
act.sa_flags = old_act->sa_flags;
|
||||
memcpy(&act.sa_mask, &old_act->sa_mask, sizeof(target_sigset_t));
|
||||
unlock_user_struct(old_act, arg2, 0);
|
||||
pact = &act;
|
||||
} else {
|
||||
pact = NULL;
|
||||
}
|
||||
ret = get_errno(do_sigaction(arg1, pact, &oact));
|
||||
if (!is_error(ret) && arg3) {
|
||||
if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
old_act->_sa_handler = oact._sa_handler;
|
||||
old_act->sa_flags = oact.sa_flags;
|
||||
memcpy(&old_act->sa_mask, &oact.sa_mask, sizeof(target_sigset_t));
|
||||
unlock_user_struct(old_act, arg3, 1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* sigprocmask(2) */
|
||||
static inline abi_long do_bsd_sigprocmask(abi_long arg1, abi_ulong arg2,
|
||||
abi_ulong arg3)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
sigset_t set, oldset, *set_ptr;
|
||||
int how;
|
||||
CPUState *cpu = thread_cpu;
|
||||
TaskState *ts = (TaskState *)cpu->opaque;
|
||||
|
||||
ret = 0;
|
||||
oldset = ts->signal_mask;
|
||||
if (arg2) {
|
||||
int i;
|
||||
|
||||
if (block_signals()) {
|
||||
return -TARGET_ERESTART;
|
||||
}
|
||||
|
||||
p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
target_to_host_sigset(&set, p);
|
||||
unlock_user(p, arg2, 0);
|
||||
set_ptr = &set;
|
||||
switch (arg1) {
|
||||
case TARGET_SIG_BLOCK:
|
||||
how = SIG_BLOCK;
|
||||
qemu_sigorset(&ts->signal_mask, &ts->signal_mask, set_ptr);
|
||||
break;
|
||||
|
||||
case TARGET_SIG_UNBLOCK:
|
||||
how = SIG_UNBLOCK;
|
||||
for (i = 1; i <= NSIG; ++i) {
|
||||
if (sigismember(set_ptr, i)) {
|
||||
sigdelset(&ts->signal_mask, i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TARGET_SIG_SETMASK:
|
||||
how = SIG_SETMASK;
|
||||
ts->signal_mask = set;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
|
||||
/* Silently ignore attempts to change blocking status of KILL or STOP */
|
||||
sigdelset(&ts->signal_mask, SIGKILL);
|
||||
sigdelset(&ts->signal_mask, SIGSTOP);
|
||||
ret = get_errno(sigprocmask(how, &ts->signal_mask, NULL));
|
||||
}
|
||||
if (!is_error(ret) && arg3) {
|
||||
p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
host_to_target_sigset(p, &oldset);
|
||||
unlock_user(p, arg3, sizeof(target_sigset_t));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* sigpending(2) */
|
||||
static inline abi_long do_bsd_sigpending(abi_long arg1)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
sigset_t set;
|
||||
|
||||
ret = get_errno(sigpending(&set));
|
||||
if (!is_error(ret)) {
|
||||
p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
host_to_target_sigset(p, &set);
|
||||
unlock_user(p, arg1, sizeof(target_sigset_t));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* sigsuspend(2) */
|
||||
static inline abi_long do_bsd_sigsuspend(void *cpu_env, abi_long arg1,
|
||||
abi_long arg2)
|
||||
{
|
||||
CPUState *cpu = env_cpu(cpu_env);
|
||||
TaskState *ts = cpu->opaque;
|
||||
void *p;
|
||||
abi_long ret;
|
||||
|
||||
p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
target_to_host_sigset(&ts->sigsuspend_mask, p);
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
ret = get_errno(sigsuspend(&ts->sigsuspend_mask));
|
||||
/* XXX Trivially true until safe_syscall */
|
||||
if (ret != -TARGET_ERESTART) {
|
||||
ts->in_sigsuspend = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* sigreturn(2) */
|
||||
static inline abi_long do_bsd_sigreturn(void *cpu_env, abi_long arg1)
|
||||
{
|
||||
|
||||
return do_sigreturn(cpu_env, arg1);
|
||||
}
|
||||
|
||||
/* sigvec(2) - not defined */
|
||||
/* sigblock(2) - not defined */
|
||||
/* sigsetmask(2) - not defined */
|
||||
/* sigstack(2) - not defined */
|
||||
|
||||
/* sigwait(2) */
|
||||
static inline abi_long do_bsd_sigwait(abi_ulong arg1, abi_ulong arg2,
|
||||
abi_long arg3)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
sigset_t set;
|
||||
int sig;
|
||||
|
||||
p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
target_to_host_sigset(&set, p);
|
||||
unlock_user(p, arg1, 0);
|
||||
ret = get_errno(sigwait(&set, &sig));
|
||||
if (!is_error(ret) && arg2) {
|
||||
ret = put_user_s32(sig, arg2);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* sigwaitinfo(2) */
|
||||
static inline abi_long do_bsd_sigwaitinfo(abi_ulong arg1, abi_ulong arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
sigset_t set;
|
||||
siginfo_t uinfo;
|
||||
|
||||
p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
target_to_host_sigset(&set, p);
|
||||
unlock_user(p, arg1, 0);
|
||||
ret = get_errno(sigwaitinfo(&set, &uinfo));
|
||||
if (!is_error(ret) && arg2) {
|
||||
p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
host_to_target_siginfo(p, &uinfo);
|
||||
unlock_user(p, arg2, sizeof(target_siginfo_t));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* sigqueue(2) */
|
||||
static inline abi_long do_bsd_sigqueue(abi_long arg1, abi_long arg2,
|
||||
abi_ulong arg3)
|
||||
{
|
||||
union sigval value;
|
||||
target_sigval_t *tvalue = (target_sigval_t *)&arg3;
|
||||
abi_ulong sival_ptr;
|
||||
|
||||
__get_user(sival_ptr, &tvalue->sival_ptr);
|
||||
value.sival_ptr = (void *)(uintptr_t)sival_ptr;
|
||||
return get_errno(sigqueue(arg1, target_to_host_signal(arg2), value));
|
||||
}
|
||||
|
||||
/* sigaltstck(2) */
|
||||
static inline abi_long do_bsd_sigaltstack(void *cpu_env, abi_ulong arg1,
|
||||
abi_ulong arg2)
|
||||
{
|
||||
|
||||
return do_sigaltstack(arg1, arg2, get_sp_from_cpustate(cpu_env));
|
||||
}
|
||||
|
||||
/* kill(2) */
|
||||
static inline abi_long do_bsd_kill(abi_long pid, abi_long sig)
|
||||
{
|
||||
|
||||
return get_errno(kill(pid, target_to_host_signal(sig)));
|
||||
}
|
||||
|
||||
/* killpg(2) */
|
||||
static inline abi_long do_bsd_killpg(abi_long pg, abi_long sig)
|
||||
{
|
||||
|
||||
return get_errno(killpg(pg, target_to_host_signal(sig)));
|
||||
}
|
||||
|
||||
#endif /* ! __BSD_SIGNAL_H_ */
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* BSD socket system call related helpers
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "qemu.h"
|
||||
#include "qemu-bsd.h"
|
||||
|
||||
/*
|
||||
* socket conversion
|
||||
*/
|
||||
abi_long target_to_host_sockaddr(struct sockaddr *addr, abi_ulong target_addr,
|
||||
socklen_t len)
|
||||
{
|
||||
const socklen_t unix_maxlen = sizeof(struct sockaddr_un);
|
||||
sa_family_t sa_family;
|
||||
struct target_sockaddr *target_saddr;
|
||||
|
||||
target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
|
||||
if (target_saddr == 0) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
|
||||
sa_family = target_saddr->sa_family;
|
||||
|
||||
/*
|
||||
* Oops. The caller might send a incomplete sun_path; sun_path
|
||||
* must be terminated by \0 (see the manual page), but unfortunately
|
||||
* it is quite common to specify sockaddr_un length as
|
||||
* "strlen(x->sun_path)" while it should be "strlen(...) + 1". We will
|
||||
* fix that here if needed.
|
||||
*/
|
||||
if (target_saddr->sa_family == AF_UNIX) {
|
||||
if (len < unix_maxlen && len > 0) {
|
||||
char *cp = (char *)target_saddr;
|
||||
|
||||
if (cp[len-1] && !cp[len]) {
|
||||
len++;
|
||||
}
|
||||
}
|
||||
if (len > unix_maxlen) {
|
||||
len = unix_maxlen;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(addr, target_saddr, len);
|
||||
addr->sa_family = sa_family; /* type uint8_t */
|
||||
addr->sa_len = target_saddr->sa_len; /* type uint8_t */
|
||||
unlock_user(target_saddr, target_addr, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long host_to_target_sockaddr(abi_ulong target_addr, struct sockaddr *addr,
|
||||
socklen_t len)
|
||||
{
|
||||
struct target_sockaddr *target_saddr;
|
||||
|
||||
target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
|
||||
if (target_saddr == 0) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
memcpy(target_saddr, addr, len);
|
||||
target_saddr->sa_family = addr->sa_family; /* type uint8_t */
|
||||
target_saddr->sa_len = addr->sa_len; /* type uint8_t */
|
||||
unlock_user(target_saddr, target_addr, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn, abi_ulong target_addr,
|
||||
socklen_t len)
|
||||
{
|
||||
struct target_ip_mreqn *target_smreqn;
|
||||
|
||||
target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
|
||||
if (target_smreqn == 0) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
|
||||
mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
|
||||
if (len == sizeof(struct target_ip_mreqn)) {
|
||||
mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex);
|
||||
}
|
||||
unlock_user(target_smreqn, target_addr, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
* socket related system call shims
|
||||
*
|
||||
* 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_SOCKET_H_
|
||||
#define __BSD_SOCKET_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "qemu-bsd.h"
|
||||
|
||||
ssize_t safe_recvfrom(int s, void *buf, size_t len, int flags,
|
||||
struct sockaddr * restrict from, socklen_t * restrict fromlen);
|
||||
ssize_t safe_sendto(int s, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *to, socklen_t tolen);
|
||||
int safe_select(int nfds, fd_set *readfs, fd_set *writefds, fd_set *exceptfds,
|
||||
struct timeval *timeout);
|
||||
int safe_pselect(int nfds, fd_set * restrict readfds,
|
||||
fd_set * restrict writefds, fd_set * restrict exceptfds,
|
||||
const struct timespec * restrict timeout,
|
||||
const sigset_t * restrict newsigmask);
|
||||
|
||||
/* bind(2) */
|
||||
static inline abi_long do_bsd_bind(int sockfd, abi_ulong target_addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
abi_long ret;
|
||||
void *addr;
|
||||
|
||||
if ((int)addrlen < 0) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
|
||||
addr = alloca(addrlen + 1);
|
||||
ret = target_to_host_sockaddr(addr, target_addr, addrlen);
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return get_errno(bind(sockfd, addr, addrlen));
|
||||
}
|
||||
|
||||
/* connect(2) */
|
||||
static inline abi_long do_bsd_connect(int sockfd, abi_ulong target_addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
abi_long ret;
|
||||
void *addr;
|
||||
|
||||
if ((int)addrlen < 0) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
addr = alloca(addrlen+1);
|
||||
|
||||
ret = target_to_host_sockaddr(addr, target_addr, addrlen);
|
||||
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return get_errno(connect(sockfd, addr, addrlen));
|
||||
}
|
||||
|
||||
/* accept(2) */
|
||||
static inline abi_long do_bsd_accept(int fd, abi_ulong target_addr,
|
||||
abi_ulong target_addrlen_addr)
|
||||
{
|
||||
socklen_t addrlen;
|
||||
void *addr;
|
||||
abi_long ret;
|
||||
|
||||
if (target_addr == 0) {
|
||||
return get_errno(accept(fd, NULL, NULL));
|
||||
}
|
||||
/* return EINVAL if addrlen pointer is invalid */
|
||||
if (get_user_u32(addrlen, target_addrlen_addr)) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
if ((int)addrlen < 0) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
addr = alloca(addrlen);
|
||||
|
||||
ret = get_errno(accept(fd, addr, &addrlen));
|
||||
if (!is_error(ret)) {
|
||||
host_to_target_sockaddr(target_addr, addr, addrlen);
|
||||
if (put_user_u32(addrlen, target_addrlen_addr)) {
|
||||
ret = -TARGET_EFAULT;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* getpeername(2) */
|
||||
static inline abi_long do_bsd_getpeername(int fd, abi_ulong target_addr,
|
||||
abi_ulong target_addrlen_addr)
|
||||
{
|
||||
socklen_t addrlen;
|
||||
void *addr;
|
||||
abi_long ret;
|
||||
|
||||
if (get_user_u32(addrlen, target_addrlen_addr)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if ((int)addrlen < 0) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
addr = alloca(addrlen);
|
||||
ret = get_errno(getpeername(fd, addr, &addrlen));
|
||||
if (!is_error(ret)) {
|
||||
host_to_target_sockaddr(target_addr, addr, addrlen);
|
||||
if (put_user_u32(addrlen, target_addrlen_addr)) {
|
||||
ret = -TARGET_EFAULT;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* getsockname(2) */
|
||||
static inline abi_long do_bsd_getsockname(int fd, abi_ulong target_addr,
|
||||
abi_ulong target_addrlen_addr)
|
||||
{
|
||||
socklen_t addrlen;
|
||||
void *addr;
|
||||
abi_long ret;
|
||||
|
||||
if (get_user_u32(addrlen, target_addrlen_addr)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if ((int)addrlen < 0) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
addr = alloca(addrlen);
|
||||
|
||||
ret = get_errno(getsockname(fd, addr, &addrlen));
|
||||
if (!is_error(ret)) {
|
||||
host_to_target_sockaddr(target_addr, addr, addrlen);
|
||||
if (put_user_u32(addrlen, target_addrlen_addr)) {
|
||||
ret = -TARGET_EFAULT;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* socketpair(2) */
|
||||
static inline abi_long do_bsd_socketpair(int domain, int type, int protocol,
|
||||
abi_ulong target_tab_addr)
|
||||
{
|
||||
int tab[2];
|
||||
abi_long ret;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, target_tab_addr, sizeof(tab[0]) * 2)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(socketpair(domain, type, protocol, tab));
|
||||
if (!is_error(ret)) {
|
||||
if (put_user_s32(tab[0], target_tab_addr) ||
|
||||
put_user_s32(tab[1], target_tab_addr + sizeof(tab[0]))) {
|
||||
ret = -TARGET_EFAULT;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* sendto(2) */
|
||||
static inline abi_long do_bsd_sendto(int fd, abi_ulong msg, size_t len,
|
||||
int flags, abi_ulong target_addr, socklen_t addrlen)
|
||||
{
|
||||
struct sockaddr *saddr;
|
||||
void *host_msg;
|
||||
abi_long ret;
|
||||
|
||||
if ((int)addrlen < 0) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
host_msg = lock_user(VERIFY_READ, msg, len, 1);
|
||||
if (!host_msg) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if (target_addr) {
|
||||
saddr = alloca(addrlen);
|
||||
ret = target_to_host_sockaddr(saddr, target_addr, addrlen);
|
||||
if (is_error(ret)) {
|
||||
unlock_user(host_msg, msg, 0);
|
||||
return ret;
|
||||
}
|
||||
ret = get_errno(safe_sendto(fd, host_msg, len, flags, saddr, addrlen));
|
||||
} else {
|
||||
ret = get_errno(send(fd, host_msg, len, flags));
|
||||
}
|
||||
unlock_user(host_msg, msg, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* recvfrom(2) */
|
||||
static inline abi_long do_bsd_recvfrom(int fd, abi_ulong msg, size_t len,
|
||||
int flags, abi_ulong target_addr, abi_ulong target_addrlen)
|
||||
{
|
||||
socklen_t addrlen;
|
||||
struct sockaddr *saddr;
|
||||
void *host_msg;
|
||||
abi_long ret;
|
||||
|
||||
host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
|
||||
if (!host_msg) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if (target_addr) {
|
||||
if (get_user_u32(addrlen, target_addrlen)) {
|
||||
ret = -TARGET_EFAULT;
|
||||
goto fail;
|
||||
}
|
||||
if ((int)addrlen < 0) {
|
||||
ret = -TARGET_EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
saddr = alloca(addrlen);
|
||||
ret = get_errno(safe_recvfrom(fd, host_msg, len, flags, saddr,
|
||||
&addrlen));
|
||||
} else {
|
||||
saddr = NULL; /* To keep compiler quiet. */
|
||||
ret = get_errno(qemu_recv(fd, host_msg, len, flags));
|
||||
}
|
||||
if (!is_error(ret)) {
|
||||
if (target_addr) {
|
||||
host_to_target_sockaddr(target_addr, saddr, addrlen);
|
||||
if (put_user_u32(addrlen, target_addrlen)) {
|
||||
ret = -TARGET_EFAULT;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
unlock_user(host_msg, msg, len);
|
||||
} else {
|
||||
fail:
|
||||
unlock_user(host_msg, msg, 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* socket(2) */
|
||||
static inline abi_long do_bsd_socket(abi_long domain, abi_long type,
|
||||
abi_long protocol)
|
||||
{
|
||||
|
||||
return get_errno(socket(domain, type, protocol));
|
||||
}
|
||||
|
||||
/* shutdown(2) */
|
||||
static inline abi_long do_bsd_shutdown(abi_long s, abi_long how)
|
||||
{
|
||||
|
||||
return get_errno(shutdown(s, how));
|
||||
}
|
||||
|
||||
#endif /* !__BSD_SOCKET_H_ */
|
|
@ -1,10 +0,0 @@
|
|||
/* Stubbed out version of core dump support, explicitly in public domain */
|
||||
|
||||
static int elf_core_dump(int signr, CPUArchState *env)
|
||||
{
|
||||
struct elf_note en = { 0 };
|
||||
|
||||
bswap_note(&en);
|
||||
|
||||
return 0;
|
||||
}
|
1311
bsd-user/elfload.c
1311
bsd-user/elfload.c
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,45 @@
|
|||
#! /bin/sh -
|
||||
|
||||
#
|
||||
# Usage: 'sh ./make_syscall_nr_h.sh [full path to syscall.h] [syscall_nr.h]'
|
||||
#
|
||||
|
||||
#default input file:
|
||||
syshdr="/usr/include/sys/syscall.h"
|
||||
|
||||
#default output file:
|
||||
sysnr="./syscall_nr.h"
|
||||
|
||||
if [ -n "$1" ]; then
|
||||
syshdr=$1
|
||||
fi
|
||||
|
||||
if [ -n "$2" ]; then
|
||||
sysnr=$2
|
||||
fi
|
||||
|
||||
echo "/*" > $sysnr
|
||||
echo " * This file was generated from $syshdr" >> $sysnr
|
||||
echo " */" >> $sysnr
|
||||
echo "" >> $sysnr
|
||||
|
||||
/usr/bin/sed -e 's:SYS_:TARGET_FREEBSD_NR_:' < $syshdr >> $sysnr
|
||||
|
||||
cat << _EOF >> $sysnr
|
||||
/* Legacy system calls. */
|
||||
#ifndef TARGET_FREEBSD_NR_killpg
|
||||
#define TARGET_FREEBSD_NR_killpg 146
|
||||
#endif
|
||||
#ifndef TARGET_FREEBSD_NR__umtx_lock
|
||||
#define TARGET_FREEBSD_NR__umtx_lock 434
|
||||
#endif
|
||||
#ifndef TARGET_FREEBSD_NR__umtx_unlock
|
||||
#define TARGET_FREEBSD_NR__umtx_unlock 435
|
||||
#endif
|
||||
#ifndef TARGET_FREEBSD_NR_cap_new
|
||||
#define TARGET_FREEBSD_NR_cap_new 514
|
||||
#endif
|
||||
#ifndef TARGET_FREEBSD_NR_cap_getrights
|
||||
#define TARGET_FREEBSD_NR_cap_getrights 515
|
||||
#endif
|
||||
_EOF
|
|
@ -1,3 +1,9 @@
|
|||
bsd_user_ss.add(files(
|
||||
'os-extattr.c',
|
||||
'os-proc.c',
|
||||
'os-socket.c',
|
||||
'os-stat.c',
|
||||
'os-sys.c',
|
||||
'os-thread.c',
|
||||
'os-time.c',
|
||||
))
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* FreeBSD extend attributes and ACL conversions
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
#define _WANT_FREEBSD11_STAT
|
||||
#define _WANT_FREEBSD11_STATFS
|
||||
#define _WANT_FREEBSD11_DIRENT
|
||||
#include <sys/types.h>
|
||||
#ifndef _ACL_PRIVATE
|
||||
#define _ACL_PRIVATE
|
||||
#endif
|
||||
#include <sys/acl.h>
|
||||
|
||||
#include "qemu.h"
|
||||
#include "qemu-os.h"
|
||||
|
||||
/*
|
||||
* FreeBSD ACL conversion.
|
||||
*/
|
||||
abi_long t2h_freebsd_acl(struct acl *host_acl, abi_ulong target_addr)
|
||||
{
|
||||
uint32_t i;
|
||||
struct target_freebsd_acl *target_acl;
|
||||
|
||||
if (!lock_user_struct(VERIFY_READ, target_acl, target_addr, 1)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__get_user(host_acl->acl_maxcnt, &target_acl->acl_maxcnt);
|
||||
__get_user(host_acl->acl_cnt, &target_acl->acl_cnt);
|
||||
|
||||
for (i = 0; i < host_acl->acl_maxcnt; i++) {
|
||||
__get_user(host_acl->acl_entry[i].ae_tag,
|
||||
&target_acl->acl_entry[i].ae_tag);
|
||||
__get_user(host_acl->acl_entry[i].ae_id,
|
||||
&target_acl->acl_entry[i].ae_id);
|
||||
__get_user(host_acl->acl_entry[i].ae_perm,
|
||||
&target_acl->acl_entry[i].ae_perm);
|
||||
__get_user(host_acl->acl_entry[i].ae_entry_type,
|
||||
&target_acl->acl_entry[i].ae_entry_type);
|
||||
__get_user(host_acl->acl_entry[i].ae_flags,
|
||||
&target_acl->acl_entry[i].ae_flags);
|
||||
}
|
||||
|
||||
unlock_user_struct(target_acl, target_addr, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long h2t_freebsd_acl(abi_ulong target_addr, struct acl *host_acl)
|
||||
{
|
||||
uint32_t i;
|
||||
struct target_freebsd_acl *target_acl;
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_acl, target_addr, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
|
||||
__put_user(host_acl->acl_maxcnt, &target_acl->acl_maxcnt);
|
||||
__put_user(host_acl->acl_cnt, &target_acl->acl_cnt);
|
||||
|
||||
for (i = 0; i < host_acl->acl_maxcnt; i++) {
|
||||
__put_user(host_acl->acl_entry[i].ae_tag,
|
||||
&target_acl->acl_entry[i].ae_tag);
|
||||
__put_user(host_acl->acl_entry[i].ae_id,
|
||||
&target_acl->acl_entry[i].ae_id);
|
||||
__put_user(host_acl->acl_entry[i].ae_perm,
|
||||
&target_acl->acl_entry[i].ae_perm);
|
||||
__put_user(host_acl->acl_entry[i].ae_entry_type,
|
||||
&target_acl->acl_entry[i].ae_entry_type);
|
||||
__put_user(host_acl->acl_entry[i].ae_flags,
|
||||
&target_acl->acl_entry[i].ae_flags);
|
||||
}
|
||||
|
||||
unlock_user_struct(target_acl, target_addr, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long t2h_freebsd_acl_type(acl_type_t *host_type, abi_long target_type)
|
||||
{
|
||||
|
||||
switch (target_type) {
|
||||
case TARGET_FREEBSD_ACL_TYPE_ACCESS_OLD:
|
||||
*host_type = ACL_TYPE_ACCESS_OLD;
|
||||
break;
|
||||
|
||||
case TARGET_FREEBSD_ACL_TYPE_DEFAULT_OLD:
|
||||
*host_type = ACL_TYPE_DEFAULT_OLD;
|
||||
break;
|
||||
|
||||
case TARGET_FREEBSD_ACL_TYPE_ACCESS:
|
||||
*host_type = ACL_TYPE_ACCESS;
|
||||
break;
|
||||
|
||||
case TARGET_FREEBSD_ACL_TYPE_DEFAULT:
|
||||
*host_type = ACL_TYPE_ACCESS;
|
||||
break;
|
||||
|
||||
case TARGET_FREEBSD_ACL_TYPE_NFS4:
|
||||
*host_type = ACL_TYPE_NFS4;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,654 @@
|
|||
/*
|
||||
* FreeBSD extended attributes and ACL system call support
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <sys/extattr.h>
|
||||
#ifndef _ACL_PRIVATE
|
||||
#define _ACL_PRIVATE
|
||||
#endif
|
||||
#include <sys/acl.h>
|
||||
|
||||
#include "qemu-os.h"
|
||||
|
||||
/* extattrctl() */
|
||||
static inline abi_long do_freebsd_extattrctl(abi_ulong arg1, abi_ulong arg2,
|
||||
abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p, *a, *f;
|
||||
|
||||
p = lock_user_string(arg1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
f = lock_user_string(arg3);
|
||||
if (f == NULL) {
|
||||
unlock_user(p, arg1, 0);
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
a = lock_user_string(arg5);
|
||||
if (a == NULL) {
|
||||
unlock_user(f, arg3, 0);
|
||||
unlock_user(p, arg1, 0);
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(extattrctl(path(p), arg2, f, arg4, a));
|
||||
unlock_user(a, arg5, 0);
|
||||
unlock_user(f, arg3, 0);
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* extattr_set_file(2) */
|
||||
static inline abi_long do_freebsd_extattr_set_file(abi_ulong arg1,
|
||||
abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p, *a, *d;
|
||||
|
||||
p = lock_user_string(arg1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
a = lock_user_string(arg3);
|
||||
if (a == NULL) {
|
||||
unlock_user(p, arg1, 0);
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
d = lock_user(VERIFY_READ, arg4, arg5, 1);
|
||||
if (d == NULL) {
|
||||
unlock_user(a, arg3, 0);
|
||||
unlock_user(p, arg1, 0);
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(extattr_set_file(path(p), arg2, a, d, arg5));
|
||||
unlock_user(d, arg4, arg5);
|
||||
unlock_user(a, arg3, 0);
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* extattr_get_file(2) */
|
||||
static inline abi_long do_freebsd_extattr_get_file(abi_ulong arg1,
|
||||
abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p, *a, *d;
|
||||
|
||||
p = lock_user_string(arg1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
a = lock_user_string(arg3);
|
||||
if (a == NULL) {
|
||||
unlock_user(p, arg1, 0);
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if (arg4 && arg5 > 0) {
|
||||
d = lock_user(VERIFY_WRITE, arg4, arg5, 0);
|
||||
if (d == NULL) {
|
||||
unlock_user(a, arg3, 0);
|
||||
unlock_user(p, arg1, 0);
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(extattr_get_file(path(p), arg2, a, d, arg5));
|
||||
unlock_user(d, arg4, arg5);
|
||||
} else {
|
||||
ret = get_errno(extattr_get_file(path(p), arg2, a, NULL, arg5));
|
||||
}
|
||||
unlock_user(a, arg3, 0);
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* extattr_delete_file(2) */
|
||||
static inline abi_long do_freebsd_extattr_delete_file(abi_ulong arg1,
|
||||
abi_long arg2, abi_ulong arg3)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p, *a;
|
||||
|
||||
p = lock_user_string(arg1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
a = lock_user_string(arg3);
|
||||
if (a == NULL) {
|
||||
unlock_user(p, arg1, 0);
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(extattr_delete_file(path(p), arg2, a));
|
||||
unlock_user(a, arg3, 0);
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* extattr_set_fd(2) */
|
||||
static inline abi_long do_freebsd_extattr_set_fd(abi_long arg1,
|
||||
abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
|
||||
{
|
||||
abi_long ret;
|
||||
void *a, *d;
|
||||
|
||||
a = lock_user_string(arg3);
|
||||
if (a == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
d = lock_user(VERIFY_READ, arg4, arg5, 1);
|
||||
if (d == NULL) {
|
||||
unlock_user(a, arg3, 0);
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(extattr_set_fd(arg1, arg2, a, d, arg5));
|
||||
unlock_user(d, arg4, arg5);
|
||||
unlock_user(a, arg3, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* extattr_get_fd(2) */
|
||||
static inline abi_long do_freebsd_extattr_get_fd(abi_long arg1,
|
||||
abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
|
||||
{
|
||||
abi_long ret;
|
||||
void *a, *d;
|
||||
|
||||
a = lock_user_string(arg3);
|
||||
if (a == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
|
||||
if (arg4 && arg5 > 0) {
|
||||
d = lock_user(VERIFY_WRITE, arg4, arg5, 0);
|
||||
if (d == NULL) {
|
||||
unlock_user(a, arg3, 0);
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(extattr_get_fd(arg1, arg2, a, d, arg5));
|
||||
unlock_user(d, arg4, arg5);
|
||||
} else {
|
||||
ret = get_errno(extattr_get_fd(arg1, arg2, a, NULL, arg5));
|
||||
}
|
||||
unlock_user(a, arg3, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* extattr_delete_fd(2) */
|
||||
static inline abi_long do_freebsd_extattr_delete_fd(abi_long arg1,
|
||||
abi_long arg2, abi_ulong arg3)
|
||||
{
|
||||
abi_long ret;
|
||||
void *a;
|
||||
|
||||
a = lock_user_string(arg3);
|
||||
if (a == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(extattr_delete_fd(arg1, arg2, a));
|
||||
unlock_user(a, arg3, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* extattr_get_link(2) */
|
||||
static inline abi_long do_freebsd_extattr_get_link(abi_ulong arg1,
|
||||
abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p, *a, *d;
|
||||
|
||||
p = lock_user_string(arg1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
a = lock_user_string(arg3);
|
||||
if (a == NULL) {
|
||||
unlock_user(p, arg1, 0);
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if (arg4 && arg5 > 0) {
|
||||
d = lock_user(VERIFY_WRITE, arg4, arg5, 0);
|
||||
if (d == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(extattr_get_link(path(p), arg2, a, d, arg5));
|
||||
unlock_user(d, arg4, arg5);
|
||||
} else {
|
||||
ret = get_errno(extattr_get_link(path(p), arg2, a, NULL, arg5));
|
||||
}
|
||||
unlock_user(a, arg3, 0);
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* extattr_set_link(2) */
|
||||
static inline abi_long do_freebsd_extattr_set_link(abi_ulong arg1,
|
||||
abi_long arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p, *a, *d;
|
||||
|
||||
p = lock_user_string(arg1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
a = lock_user_string(arg3);
|
||||
if (a == NULL) {
|
||||
unlock_user(p, arg1, 0);
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
d = lock_user(VERIFY_READ, arg4, arg5, 1);
|
||||
if (d == NULL) {
|
||||
unlock_user(a, arg3, 0);
|
||||
unlock_user(p, arg1, 0);
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(extattr_set_link(path(p), arg2, a, d, arg5));
|
||||
unlock_user(d, arg4, arg5);
|
||||
unlock_user(a, arg3, 0);
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* extattr_delete_link(2) */
|
||||
static inline abi_long do_freebsd_extattr_delete_link(abi_ulong arg1,
|
||||
abi_long arg2, abi_ulong arg3)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p, *a;
|
||||
|
||||
p = lock_user_string(arg1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
a = lock_user_string(arg3);
|
||||
if (a == NULL) {
|
||||
unlock_user(p, arg1, 0);
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(extattr_delete_link(path(p), arg2, a));
|
||||
unlock_user(a, arg3, 0);
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* extattr_list_fd(2) */
|
||||
static inline abi_long do_freebsd_extattr_list_fd(abi_long arg1, abi_long arg2,
|
||||
abi_ulong arg3, abi_ulong arg4)
|
||||
{
|
||||
abi_long ret;
|
||||
void *d;
|
||||
|
||||
if (arg3 && arg4 > 0) {
|
||||
d = lock_user(VERIFY_WRITE, arg3, arg4, 0);
|
||||
if (d == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(extattr_list_fd(arg1, arg2, d, arg4));
|
||||
unlock_user(d, arg3, arg4);
|
||||
} else {
|
||||
ret = get_errno(extattr_list_fd(arg1, arg2, NULL, arg4));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* extattr_list_file(2) */
|
||||
static inline abi_long do_freebsd_extattr_list_file(abi_long arg1,
|
||||
abi_long arg2, abi_ulong arg3, abi_ulong arg4)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p, *d;
|
||||
|
||||
p = lock_user_string(arg1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if (arg3 && arg4 > 0) {
|
||||
d = lock_user(VERIFY_WRITE, arg3, arg4, 0);
|
||||
if (d == NULL) {
|
||||
unlock_user(p, arg1, 0);
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(extattr_list_file(path(p), arg2, d, arg4));
|
||||
unlock_user(d, arg3, arg4);
|
||||
} else {
|
||||
ret = get_errno(extattr_list_file(path(p), arg2, NULL, arg4));
|
||||
}
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* extattr_list_link(2) */
|
||||
static inline abi_long do_freebsd_extattr_list_link(abi_long arg1,
|
||||
abi_long arg2, abi_ulong arg3, abi_ulong arg4)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p, *d;
|
||||
|
||||
p = lock_user_string(arg1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if (arg3 && arg4 > 0) {
|
||||
d = lock_user(VERIFY_WRITE, arg3, arg4, 0);
|
||||
if (d == NULL) {
|
||||
unlock_user(p, arg1, 0);
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(extattr_list_link(path(p), arg2, d, arg4));
|
||||
unlock_user(d, arg3, arg4);
|
||||
} else {
|
||||
ret = get_errno(extattr_list_link(path(p), arg2, NULL, arg4));
|
||||
}
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Access Control Lists
|
||||
*/
|
||||
|
||||
/* __acl_aclcheck_fd(int filedes, acl_type_t type, struct acl *aclp); */
|
||||
static inline abi_long do_freebsd__acl_aclcheck_fd(abi_long arg1, abi_long arg2,
|
||||
abi_ulong arg3)
|
||||
{
|
||||
abi_long ret;
|
||||
struct acl host_acl;
|
||||
acl_type_t type;
|
||||
|
||||
ret = t2h_freebsd_acl_type(&type, arg2);
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
ret = t2h_freebsd_acl(&host_acl, arg3);
|
||||
if (!is_error(ret)) {
|
||||
ret = get_errno(__acl_aclcheck_fd(arg1, type, &host_acl));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* __acl_aclcheck_file(const char *path, acl_type_t type, struct acl *aclp); */
|
||||
static inline abi_long do_freebsd__acl_aclcheck_file(abi_ulong arg1,
|
||||
abi_long arg2, abi_ulong arg3)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
struct acl host_acl;
|
||||
acl_type_t type;
|
||||
|
||||
ret = t2h_freebsd_acl_type(&type, arg2);
|
||||
p = lock_user_string(arg1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = t2h_freebsd_acl(&host_acl, arg3);
|
||||
if (!is_error(ret)) {
|
||||
ret = get_errno(__acl_aclcheck_file(path(p) , arg2, &host_acl));
|
||||
}
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* __acl_aclcheck_link(const char *path, acl_type_t type, struct acl *aclp); */
|
||||
static inline abi_long do_freebsd__acl_aclcheck_link(abi_ulong arg1,
|
||||
abi_long arg2, abi_ulong arg3)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
struct acl host_acl;
|
||||
acl_type_t type;
|
||||
|
||||
ret = t2h_freebsd_acl_type(&type, arg2);
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
p = lock_user_string(arg1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = t2h_freebsd_acl(&host_acl, arg3);
|
||||
if (!is_error(ret)) {
|
||||
ret = get_errno(__acl_aclcheck_link(path(p), type, &host_acl));
|
||||
}
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* int __acl_delete_fd(int filedes, acl_type_t type); */
|
||||
static inline abi_long do_freebsd__acl_delete_fd(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
acl_type_t type;
|
||||
|
||||
ret = t2h_freebsd_acl_type(&type, arg2);
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
return get_errno(__acl_delete_fd(arg1, type));
|
||||
}
|
||||
|
||||
/* int __acl_delete_file(const char *path, acl_type_t type); */
|
||||
static inline abi_long do_freebsd__acl_delete_file(abi_ulong arg1,
|
||||
abi_long arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
acl_type_t type;
|
||||
|
||||
ret = t2h_freebsd_acl_type(&type, arg2);
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
p = lock_user_string(arg1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(__acl_delete_file(path(p), type));
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* int __acl_delete_link(const char *path, acl_type_t type); */
|
||||
static inline abi_long do_freebsd__acl_delete_link(abi_ulong arg1,
|
||||
abi_long arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
acl_type_t type;
|
||||
|
||||
ret = t2h_freebsd_acl_type(&type, arg2);
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
p = lock_user_string(arg1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(__acl_delete_link(path(p), type));
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); */
|
||||
static inline abi_long do_freebsd__acl_get_fd(abi_long arg1, abi_long arg2,
|
||||
abi_ulong arg3)
|
||||
{
|
||||
abi_long ret;
|
||||
acl_type_t type;
|
||||
struct acl host_acl;
|
||||
|
||||
bzero(&host_acl, sizeof(struct acl));
|
||||
host_acl.acl_maxcnt = ACL_MAX_ENTRIES;
|
||||
|
||||
ret = t2h_freebsd_acl_type(&type, arg2);
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
ret = get_errno(__acl_get_fd(arg1, type, &host_acl));
|
||||
if (!is_error(ret)) {
|
||||
ret = h2t_freebsd_acl(arg3, &host_acl);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* __acl_get_file(const char *path, acl_type_t type, struct acl *aclp); */
|
||||
static inline abi_long do_freebsd__acl_get_file(abi_ulong arg1, abi_long arg2,
|
||||
abi_ulong arg3)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
acl_type_t type;
|
||||
struct acl host_acl;
|
||||
|
||||
bzero(&host_acl, sizeof(struct acl));
|
||||
host_acl.acl_maxcnt = ACL_MAX_ENTRIES;
|
||||
|
||||
ret = t2h_freebsd_acl_type(&type, arg2);
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
p = lock_user_string(arg1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(__acl_get_file(path(p), type, &host_acl));
|
||||
if (!is_error(ret)) {
|
||||
ret = h2t_freebsd_acl(arg3, &host_acl);
|
||||
}
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* int __acl_get_link(const char *path, acl_type_t type, struct acl *aclp); */
|
||||
static inline abi_long do_freebsd__acl_get_link(abi_ulong arg1, abi_long arg2,
|
||||
abi_ulong arg3)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
acl_type_t type;
|
||||
struct acl host_acl;
|
||||
|
||||
bzero(&host_acl, sizeof(struct acl));
|
||||
host_acl.acl_maxcnt = ACL_MAX_ENTRIES;
|
||||
|
||||
ret = t2h_freebsd_acl_type(&type, arg2);
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
p = lock_user_string(arg1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(__acl_get_link(path(p), type, &host_acl));
|
||||
if (!is_error(ret)) {
|
||||
ret = h2t_freebsd_acl(arg3, &host_acl);
|
||||
}
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* int __acl_set_fd(int filedes, acl_type_t type, struct acl *aclp); */
|
||||
static inline abi_long do_freebsd__acl_set_fd(abi_long arg1, abi_long arg2,
|
||||
abi_ulong arg3)
|
||||
{
|
||||
abi_long ret;
|
||||
acl_type_t type;
|
||||
struct acl host_acl;
|
||||
|
||||
ret = t2h_freebsd_acl_type(&type, arg2);
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
ret = t2h_freebsd_acl(&host_acl, arg3);
|
||||
if (!is_error(ret)) {
|
||||
ret = get_errno(__acl_set_fd(arg1, type, &host_acl));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* int __acl_set_file(const char *path, acl_type_t type, struct acl *aclp); */
|
||||
static inline abi_long do_freebsd__acl_set_file(abi_ulong arg1, abi_long arg2,
|
||||
abi_ulong arg3)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
acl_type_t type;
|
||||
struct acl host_acl;
|
||||
|
||||
ret = t2h_freebsd_acl_type(&type, arg2);
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
p = lock_user_string(arg1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = t2h_freebsd_acl(&host_acl, arg3);
|
||||
if (!is_error(ret)) {
|
||||
ret = get_errno(__acl_set_file(path(p), type, &host_acl));
|
||||
}
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* int __acl_set_link(const char *path, acl_type_t type, struct acl *aclp); */
|
||||
static inline abi_long do_freebsd__acl_set_link(abi_ulong arg1, abi_long arg2,
|
||||
abi_ulong arg3)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
acl_type_t type;
|
||||
struct acl host_acl;
|
||||
|
||||
ret = t2h_freebsd_acl_type(&type, arg2);
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
p = lock_user_string(arg1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = t2h_freebsd_acl(&host_acl, arg3);
|
||||
if (!is_error(ret)) {
|
||||
ret = get_errno(__acl_set_link(path(p), type, &host_acl));
|
||||
}
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
* FreeBSD file related system call shims and definitions
|
||||
*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __FREEBSD_OS_FILE_H_
|
||||
#define __FREEBSD_OS_FILE_H_
|
||||
|
||||
#define _WANT_FREEBSD11_STAT
|
||||
#define _WANT_FREEBSD11_STATFS
|
||||
#define _WANT_FREEBSD11_DIRENT
|
||||
#include <sys/stat.h>
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 1300133
|
||||
#include <sys/specialfd.h>
|
||||
#endif
|
||||
|
||||
#include <aio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "qemu-os.h"
|
||||
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 1300133
|
||||
int __sys___specialfd(int, const void *, size_t);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Asynchronous I/O.
|
||||
*/
|
||||
|
||||
/* aio_read(2) */
|
||||
static abi_long do_freebsd_aio_read(__unused abi_ulong iocb)
|
||||
{
|
||||
qemu_log("qemu: Unsupported syscall aio_read()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* aio_write(2) */
|
||||
static abi_long do_freebsd_aio_write(__unused abi_ulong iocb)
|
||||
{
|
||||
qemu_log("qemu: Unsupported syscall aio_write()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* aio_suspend(2) */
|
||||
static abi_long do_freebsd_aio_suspend(__unused abi_ulong iocbs,
|
||||
__unused int niocb, __unused abi_ulong timeout)
|
||||
{
|
||||
qemu_log("qemu: Unsupported syscall aio_suspend()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* aio_cancel(2) */
|
||||
static abi_long do_freebsd_aio_cancel(__unused int fildes,
|
||||
__unused abi_ulong iocb)
|
||||
{
|
||||
qemu_log("qemu: Unsupported syscall aio_cancel()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* aio_error(2) */
|
||||
static abi_long do_freebsd_aio_error(__unused abi_ulong iocb)
|
||||
{
|
||||
qemu_log("qemu: Unsupported syscall aio_error()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* aio_waitcomplete(2) */
|
||||
static abi_long do_freebsd_aio_waitcomplete(__unused abi_ulong iocbp,
|
||||
__unused abi_ulong timeout)
|
||||
{
|
||||
qemu_log("qemu: Unsupported syscall aio_waitcomplete()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* aio_fsync(2) */
|
||||
static abi_long do_freebsd_aio_fsync(__unused int op,
|
||||
__unused abi_ulong iocb)
|
||||
{
|
||||
qemu_log("qemu: Unsupported syscall aio_fsync()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* aio_mlock(2) */
|
||||
static abi_long do_freebsd_aio_mlock(__unused abi_ulong iocb)
|
||||
{
|
||||
qemu_log("qemu: Unsupported syscall aio_mlock()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 1000000
|
||||
/* pipe2(2) */
|
||||
static abi_long do_bsd_pipe2(void *cpu_env, abi_ulong pipedes, int flags)
|
||||
{
|
||||
int host_pipe[2];
|
||||
int host_ret = pipe2(host_pipe, flags); /* XXXss - flags should be
|
||||
translated from target to host. */
|
||||
|
||||
if (is_error(host_ret)) {
|
||||
return get_errno(host_ret);
|
||||
}
|
||||
/*
|
||||
* XXX pipe2() returns it's second FD by copying it back to
|
||||
* userspace and not in a second register like pipe(2):
|
||||
* set_second_rval(cpu_env, host_pipe[1]);
|
||||
*
|
||||
* Copy the FD's back to userspace:
|
||||
*/
|
||||
if (put_user_s32(host_pipe[0], pipedes) ||
|
||||
put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0]))) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* chflagsat(2) */
|
||||
static inline abi_long do_bsd_chflagsat(int fd, abi_ulong path,
|
||||
abi_ulong flags, int atflags)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
|
||||
LOCK_PATH(p, path);
|
||||
ret = get_errno(chflagsat(fd, p, flags, atflags)); /* XXX path(p)? */
|
||||
UNLOCK_PATH(p, path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else /* ! __FreeBSD_version > 1000000 */
|
||||
|
||||
static abi_long do_bsd_pipe2(__unused void *cpu_env, __unused abi_long arg1,
|
||||
__unused int flags)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall pipe2()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
static inline abi_long do_bsd_chflagsat(__unused int fd,
|
||||
__unused abi_ulong path, __unused abi_ulong flags, int atflags)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall chflagsat()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
#endif /* ! __FreeBSD_version >= 1000000 */
|
||||
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 1300091
|
||||
/* close_range(2) */
|
||||
static inline abi_long do_freebsd_close_range(unsigned int lowfd,
|
||||
unsigned int highfd, int flags)
|
||||
{
|
||||
|
||||
return (close_range(lowfd, highfd, flags));
|
||||
}
|
||||
|
||||
#endif /* __FreeBSD_version >= 1300091 */
|
||||
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 1300037
|
||||
ssize_t safe_copy_file_range(int, off_t *, int, off_t *, size_t, unsigned int);
|
||||
|
||||
/* copy_file_range(2) */
|
||||
static inline abi_long do_freebsd_copy_file_range(int infd,
|
||||
abi_ulong inofftp, int outfd, abi_ulong outofftp, size_t len,
|
||||
unsigned int flags)
|
||||
{
|
||||
off_t inoff, outoff, *inp, *outp;
|
||||
abi_long ret;
|
||||
|
||||
inp = outp = NULL;
|
||||
if (inofftp != 0 && !access_ok(VERIFY_WRITE, inofftp, sizeof(off_t))) {
|
||||
return -TARGET_EFAULT;
|
||||
} else if (inofftp != 0) {
|
||||
inoff = tswap64(*(off_t *)g2h_untagged(inofftp));
|
||||
inp = &inoff;
|
||||
}
|
||||
if (outofftp != 0 && !access_ok(VERIFY_WRITE, outofftp, sizeof(off_t))) {
|
||||
return -TARGET_EFAULT;
|
||||
} else if (outofftp != 0) {
|
||||
outoff = tswap64(*(off_t *)g2h_untagged(outofftp));
|
||||
outp = &outoff;
|
||||
}
|
||||
|
||||
ret = get_errno(safe_copy_file_range(infd, inp, outfd, outp, len,
|
||||
flags));
|
||||
|
||||
if (inofftp != 0)
|
||||
*(off_t *)g2h_untagged(inofftp) = tswap64(inoff);
|
||||
if (outofftp != 0)
|
||||
*(off_t *)g2h_untagged(outofftp) = tswap64(outoff);
|
||||
return ret;
|
||||
}
|
||||
#endif /* __FreeBSD_version >= 1300037 */
|
||||
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 1300133
|
||||
|
||||
static inline abi_long do_freebsd___specialfd(int type, abi_ulong req,
|
||||
size_t len)
|
||||
{
|
||||
abi_long ret;
|
||||
|
||||
ret = -TARGET_EINVAL;
|
||||
switch (type) {
|
||||
case TARGET_SPECIALFD_EVENT: {
|
||||
struct specialfd_eventfd evfd;
|
||||
struct target_specialfd_eventfd *target_eventfd;
|
||||
|
||||
if (!lock_user_struct(VERIFY_READ, target_eventfd, req, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
|
||||
evfd.initval = tswap32(target_eventfd->initval);
|
||||
evfd.flags = tswap32(target_eventfd->flags);
|
||||
ret = get_errno(__sys___specialfd(type, &evfd, sizeof(evfd)));
|
||||
unlock_user_struct(target_eventfd, req, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* __FreeBSD_version >= 1300037 */
|
||||
|
||||
#endif /* __FREEBSD_OS_FILE_H_ */
|
|
@ -0,0 +1,140 @@
|
|||
|
||||
/* sys/ttycom.h tty(4) */
|
||||
IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT))
|
||||
IOCTL(TIOCGETD, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(TIOCSBRK, IOC_, TYPE_NULL)
|
||||
IOCTL(TIOCCBRK, IOC_, TYPE_NULL)
|
||||
IOCTL(TIOCSDTR, IOC_, TYPE_NULL)
|
||||
IOCTL(TIOCCDTR, IOC_, TYPE_NULL)
|
||||
IOCTL(TIOCGPGRP, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(TIOCSPGRP, IOC_W, MK_PTR(TYPE_INT))
|
||||
IOCTL(TIOCGETA, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
|
||||
IOCTL(TIOCSETA, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
|
||||
IOCTL(TIOCSETAW, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
|
||||
IOCTL(TIOCSETAF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
|
||||
IOCTL(TIOCPTMASTER, IOC_, TYPE_NULL)
|
||||
IOCTL(TIOCOUTQ, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(TIOCSTI, IOC_W, MK_PTR(TYPE_CHAR))
|
||||
IOCTL(TIOCNOTTY, IOC_, TYPE_NULL)
|
||||
IOCTL(TIOCSTOP, IOC_, TYPE_NULL)
|
||||
IOCTL(TIOCSTART, IOC_, TYPE_NULL)
|
||||
IOCTL(TIOCPKT, IOC_W, MK_PTR(TYPE_INT))
|
||||
IOCTL(TIOCSCTTY, IOC_, TYPE_NULL)
|
||||
IOCTL(TIOCDRAIN, IOC_, TYPE_NULL)
|
||||
IOCTL(TIOCEXCL, IOC_, TYPE_NULL)
|
||||
IOCTL(TIOCNXCL, IOC_, TYPE_NULL)
|
||||
IOCTL(TIOCFLUSH, IOC_W, MK_PTR(TYPE_INT))
|
||||
IOCTL(TIOCGWINSZ, IOC_R, MK_PTR(MK_STRUCT(STRUCT_winsize)))
|
||||
IOCTL(TIOCSWINSZ, IOC_W, MK_PTR(MK_STRUCT(STRUCT_winsize)))
|
||||
IOCTL(TIOCCONS, IOC_W, MK_PTR(TYPE_INT))
|
||||
IOCTL(TIOCMSET, IOC_W, MK_PTR(TYPE_INT))
|
||||
IOCTL(TIOCMGET, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(TIOCMBIS, IOC_W, MK_PTR(TYPE_INT))
|
||||
IOCTL(TIOCMBIC, IOC_W, MK_PTR(TYPE_INT))
|
||||
|
||||
/* sys/filio.h */
|
||||
IOCTL(FIOCLEX, IOC_, TYPE_NULL)
|
||||
IOCTL(FIONCLEX, IOC_, TYPE_NULL)
|
||||
IOCTL(FIONREAD, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(FIONBIO, IOC_W, MK_PTR(TYPE_INT))
|
||||
IOCTL(FIOASYNC, IOC_W, MK_PTR(TYPE_INT))
|
||||
IOCTL(FIOSETOWN, IOC_W, MK_PTR(TYPE_INT))
|
||||
IOCTL(FIOGETOWN, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(FIODTYPE, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(FIOGETLBA, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(FIODGNAME, IOC_W, MK_PTR(MK_STRUCT(STRUCT_fiodgname_arg)))
|
||||
IOCTL(FIONWRITE, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(FIONSPACE, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(FIOSEEKDATA, IOC_RW, MK_PTR(TYPE_ULONG))
|
||||
IOCTL(FIOSEEKHOLE, IOC_RW, MK_PTR(TYPE_ULONG))
|
||||
|
||||
/* crypto/cryptodev.h */
|
||||
IOCTL_SPECIAL(CIOCGSESSION, IOC_RW, do_ioctl_unsupported, TYPE_INT)
|
||||
IOCTL_SPECIAL_UNIMPL(CRIOGET, IOC_RW, do_ioctl_unsupported, TYPE_INT)
|
||||
|
||||
/* netinet6/in6_var.h */
|
||||
IOCTL_SPECIAL(SIOCGIFAFLAG_IN6, IOC_RW, do_ioctl_in6_ifreq_sockaddr_int, MK_PTR(MK_STRUCT(STRUCT_in6_ifreq_int)))
|
||||
IOCTL_SPECIAL(SIOCGIFALIFETIME_IN6, IOC_RW, do_ioctl_in6_ifreq_sockaddr_int, MK_PTR(MK_STRUCT(STRUCT_in6_ifreq_int)))
|
||||
IOCTL(SIOCGIFPSRCADDR_IN6, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_in6_ifreq_sockaddr_in6)))
|
||||
IOCTL(SIOCGIFINFO_IN6, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_in6_ndireq)))
|
||||
IOCTL(SIOCGDEFIFACE_IN6, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_in6_ndifreq)))
|
||||
|
||||
/* sys/disk.h */
|
||||
IOCTL(DIOCGSECTORSIZE, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(DIOCGMEDIASIZE, IOC_R, MK_PTR(TYPE_LONGLONG))
|
||||
|
||||
/* sys/sockio.h */
|
||||
IOCTL_SPECIAL(SIOCGIFMAC, IOC_RW, do_ioctl_unsupported, MK_PTR(MK_STRUCT(STRUCT_ifreq_int)))
|
||||
|
||||
IOCTL(SIOCGIFCONF, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_ifconf)))
|
||||
|
||||
IOCTL(SIOCGIFFLAGS, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifreq_short)))
|
||||
IOCTL(SIOCSIFFLAGS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_ifreq_short)))
|
||||
|
||||
IOCTL(SIOCGIFMETRIC, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifreq_int)))
|
||||
IOCTL(SIOCSIFMETRIC, IOC_W, MK_PTR(MK_STRUCT(STRUCT_ifreq_int)))
|
||||
IOCTL(SIOCGIFMTU, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifreq_int)))
|
||||
IOCTL(SIOCSIFMTU, IOC_W, MK_PTR(MK_STRUCT(STRUCT_ifreq_int)))
|
||||
IOCTL(SIOCGIFINDEX, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifreq_int)))
|
||||
IOCTL(SIOCGIFFIB, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifreq_int)))
|
||||
#ifdef SIOCGTUNFIB
|
||||
IOCTL(SIOCGTUNFIB, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifreq_int)))
|
||||
#endif
|
||||
|
||||
IOCTL(SIOCGIFCAP, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifreq_cap)))
|
||||
|
||||
IOCTL(SIOCGIFADDR, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifreq_sockaddr)))
|
||||
IOCTL(SIOCSIFADDR, IOC_W, MK_PTR(MK_STRUCT(STRUCT_ifreq_sockaddr)))
|
||||
IOCTL(SIOCGIFBRDADDR, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifreq_sockaddr)))
|
||||
IOCTL(SIOCSIFBRDADDR, IOC_W, MK_PTR(MK_STRUCT(STRUCT_ifreq_sockaddr)))
|
||||
IOCTL(SIOCGIFDSTADDR, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifreq_sockaddr)))
|
||||
IOCTL(SIOCSIFDSTADDR, IOC_W, MK_PTR(MK_STRUCT(STRUCT_ifreq_sockaddr)))
|
||||
IOCTL(SIOCGIFNETMASK, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifreq_sockaddr)))
|
||||
IOCTL(SIOCSIFNETMASK, IOC_W, MK_PTR(MK_STRUCT(STRUCT_ifreq_sockaddr)))
|
||||
IOCTL(SIOCADDMULTI, IOC_W, MK_PTR(MK_STRUCT(STRUCT_ifreq_sockaddr)))
|
||||
IOCTL(SIOCDELMULTI, IOC_W, MK_PTR(MK_STRUCT(STRUCT_ifreq_sockaddr)))
|
||||
IOCTL(SIOCGIFPSRCADDR, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifreq_sockaddr)))
|
||||
|
||||
IOCTL(SIOCGIFGENERIC, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifreq_ptr)))
|
||||
|
||||
IOCTL(SIOCGIFDESCR, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifreq_buf)))
|
||||
|
||||
IOCTL(SIOCGDRVSPEC, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifdrv)))
|
||||
|
||||
IOCTL(SIOCGIFGROUP, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifgroupreq_ptr)))
|
||||
|
||||
IOCTL(SIOCGIFMEDIA, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifmediareq)))
|
||||
#ifdef SIOCGIFXMEDIA
|
||||
IOCTL(SIOCGIFXMEDIA, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifmediareq)))
|
||||
#endif
|
||||
|
||||
IOCTL(SIOCGIFSTATUS, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifstat)))
|
||||
|
||||
/* net/if_gre.h */
|
||||
IOCTL(GREGKEY, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifreq_ptr)))
|
||||
#ifdef GREGOPTS
|
||||
IOCTL(GREGOPTS, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifreq_ptr)))
|
||||
#endif
|
||||
|
||||
/* net/if_gif.h */
|
||||
IOCTL(GIFGOPTS, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifreq_ptr)))
|
||||
|
||||
/* netinet/ip_carp.h */
|
||||
IOCTL(SIOCGVH, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifreq_ptr)))
|
||||
|
||||
/* net/if_pfsync.h */
|
||||
#ifdef SIOCGETPFSYNC
|
||||
IOCTL(SIOCGETPFSYNC, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifreq_ptr)))
|
||||
#endif
|
||||
|
||||
/* net80211/ieee80211_ioctl.h */
|
||||
IOCTL(SIOCG80211, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ieee80211req)))
|
||||
|
||||
/* net/if_lagg.h */
|
||||
IOCTL(SIOCGLAGGPORT, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_lagg_reqport_lacp_opreq)))
|
||||
IOCTL(SIOCGLAGG, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_lagg_reqall_lacp_opreq)))
|
||||
IOCTL(SIOCGLAGGFLAGS, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_lagg_reqflags)))
|
||||
#ifdef SIOCGLAGGOPTS
|
||||
IOCTL(SIOCGLAGGOPTS, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_lagg_reqopts)))
|
||||
#endif
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* FreeBSD cryptodev definitions for ioctl(2) emulation
|
||||
*
|
||||
* Copyright (c) 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/>.
|
||||
*/
|
||||
#ifndef _IOCTL_CRYPTODEV_H_
|
||||
#define _IOCTL_CRYPTODEV_H_
|
||||
|
||||
/* see opencrypto/cryptodev.h */
|
||||
|
||||
struct target_session_op {
|
||||
u_int32_t cipher;
|
||||
u_int32_t mac;
|
||||
|
||||
u_int32_t keylen;
|
||||
abi_ulong key;
|
||||
int32_t mackeylen;
|
||||
abi_ulong mackey;
|
||||
|
||||
u_int32_t ses;
|
||||
};
|
||||
|
||||
|
||||
struct target_session2_op {
|
||||
u_int32_t cipher;
|
||||
u_int32_t mac;
|
||||
|
||||
u_int32_t keylen;
|
||||
abi_ulong key;
|
||||
int32_t mackeylen;
|
||||
abi_ulong mackey;
|
||||
|
||||
u_int32_t ses;
|
||||
int32_t crid;
|
||||
int pad[4];
|
||||
};
|
||||
|
||||
struct target_crypt_find_op {
|
||||
int crid;
|
||||
char name[32];
|
||||
};
|
||||
|
||||
struct target_crparam {
|
||||
abi_ulong crp_p;
|
||||
u_int crp_nbits;
|
||||
};
|
||||
|
||||
#define TARGET_CRK_MAXPARAM 8
|
||||
|
||||
struct target_crypt_kop {
|
||||
u_int crk_op;
|
||||
u_int crk_status;
|
||||
u_short crk_iparams;
|
||||
u_short crk_oparams;
|
||||
u_int crk_crid;
|
||||
struct target_crparam crk_param[TARGET_CRK_MAXPARAM];
|
||||
};
|
||||
|
||||
#define TARGET_CRIOGET TARGET_IOWR('c', 100, u_int32_t)
|
||||
#define TARGET_CRIOASYMFEAT TARGET_CIOCASYMFEAT
|
||||
#define TARGET_CRIOFINDDEV TARGET_CIOCFINDDEV
|
||||
|
||||
#define TARGET_CIOCGSESSION TARGET_IOWR('c', 101, struct target_session_op)
|
||||
#define TARGET_CIOCFSESSION TARGET_IOW('c', 102, u_int32_t)
|
||||
#define TARGET_CIOCCRYPT TARGET_IOWR('c', 103, struct target_crypt_op)
|
||||
#define TARGET_CIOCKEY TARGET_IOWR('c', 104, struct target_crypt_kop)
|
||||
#define TARGET_CIOCASYMFEAT TARGET_IOR('c', 105, u_int32_t)
|
||||
#define TARGET_CIOCGSESSION2 TARGET_IOWR('c', 106, struct target_session2_op)
|
||||
#define TARGET_CIOCKEY2 TARGET_IOWR('c', 107, struct target_crypt_kop)
|
||||
#define TARGET_CIOCFINDDEV TARGET_IOWR('c', 108, struct target_crypt_find_op)
|
||||
|
||||
#endif /* !_IOCTL_CRYPTODEV_H_ */
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* FreeBSD disk.h definitions for ioctl(2) emulation
|
||||
*
|
||||
* Copyright (c) 2015 Stacey D. Son
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 _OS_IOCTL_DISK_H_
|
||||
#define _OS_IOCTL_DISK_H_
|
||||
|
||||
/* See sys/disk.h */
|
||||
|
||||
#define TARGET_DIOCGSECTORSIZE TARGET_IOR('d', 128, uint32_t)
|
||||
#define TARGET_DIOCGMEDIASIZE TARGET_IOR('d', 129, int64_t)
|
||||
#define TARGET_DIOCGFWSECTORS TARGET_IOR('d', 130, uint32_t)
|
||||
#define TARGET_DIOCGFWHEADS TARGET_IOR('d', 131, uint32_t)
|
||||
#define TARGET_DIOCSKERNELDUMP TARGET_IOW('d', 133, uint32_t)
|
||||
#define TARGET_DIOCGFRONTSTUFF TARGET_IOR('d', 134, int64_t)
|
||||
#define TARGET_DIOCGFLUSH TARGET_IO('d', 135)
|
||||
#define TARGET_DIOCGDELETE TARGET_IOW('d', 136, int64_t[2])
|
||||
#define TARGET_DISK_IDENT_SIZE 256
|
||||
#define TARGET_DIOCGIDENT TARGET_IOR('d', 137, \
|
||||
char[TARGET_DISK_IDENT_SIZE])
|
||||
#define TARGET_DIOCGPROVIDERNAME TARGET_IOR('d', 138, char[MAXPATHLEN])
|
||||
#define TARGET_DIOCGSTRIPESIZE TARGET_IOR('d', 139, int64_t)
|
||||
#define TARGET_DIOCGSTRIPEOFFSET TARGET_IOR('d', 140, int64_t)
|
||||
#define TARGET_DIOCGPHYSPATH TARGET_IOR('d', 141, char[MAXPATHLEN])
|
||||
|
||||
struct target_diocgattr_arg {
|
||||
char name[64];
|
||||
int32_t len;
|
||||
union {
|
||||
char str[TARGET_DISK_IDENT_SIZE];
|
||||
int64_t off;
|
||||
int32_t i;
|
||||
} value;
|
||||
};
|
||||
|
||||
#define TARGET_DIOCGATTR TARGET_IOWR('d', 142, struct target_diocgattr_arg)
|
||||
|
||||
#endif /* _OS_IOCTL_DISK_H_ */
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* FreeBSD filio definitions for ioctl(2) emulation
|
||||
*
|
||||
* 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 _IOCTL_FILIO_H_
|
||||
#define _IOCTL_FILIO_H_
|
||||
|
||||
/* see sys/filio.h */
|
||||
#define TARGET_FIOCLEX TARGET_IO('f', 1)
|
||||
#define TARGET_FIONCLEX TARGET_IO('f', 2)
|
||||
#define TARGET_FIONREAD TARGET_IOR('f', 127, int)
|
||||
#define TARGET_FIONBIO TARGET_IOW('f', 126, int)
|
||||
#define TARGET_FIOASYNC TARGET_IOW('f', 125, int)
|
||||
#define TARGET_FIOSETOWN TARGET_IOW('f', 124, int)
|
||||
#define TARGET_FIOGETOWN TARGET_IOR('f', 123, int)
|
||||
#define TARGET_FIODTYPE TARGET_IOR('f', 122, int)
|
||||
#define TARGET_FIOGETLBA TARGET_IOR('f', 121, int)
|
||||
|
||||
struct target_fiodgname_arg {
|
||||
int32_t len;
|
||||
abi_ulong buf;
|
||||
};
|
||||
|
||||
#define TARGET_FIODGNAME TARGET_IOW('f', 120, \
|
||||
struct target_fiodgname_arg)
|
||||
#define TARGET_FIONWRITE TARGET_IOR('f', 119, int)
|
||||
#define TARGET_FIONSPACE TARGET_IOR('f', 118, int)
|
||||
#define TARGET_FIOSEEKDATA TARGET_IOWR('f', 97, off_t)
|
||||
#define TARGET_FIOSEEKHOLE TARGET_IOWR('f', 98, off_t)
|
||||
|
||||
#endif /* !_IOCTL_FILIO_H_ */
|
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
* FreeBSD in6 definitions for ioctl(2) emulation
|
||||
*
|
||||
* Copyright (c) 2014-15 Stacey D. Son
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 _IOCTL_IN6_VAR_H_
|
||||
#define _IOCTL_IN6_VAR_H_
|
||||
|
||||
/* see netinet6/in6_var.h */
|
||||
|
||||
/* and see netinet/in6.h
|
||||
* XXX target_in6_addr and target_sockaddr_in6 should maybe go
|
||||
* somewhere else.
|
||||
*/
|
||||
struct target_in6_addr {
|
||||
union {
|
||||
uint8_t __u6_addr8[16];
|
||||
uint16_t __u6_addr16[8];
|
||||
uint32_t __u6_addr32[4];
|
||||
} __u6_addr;
|
||||
};
|
||||
|
||||
struct target_sockaddr_in6 {
|
||||
uint8_t sin6_len;
|
||||
uint8_t sin6_family;
|
||||
uint16_t sin6_port;
|
||||
uint32_t sin6_flowinfo;
|
||||
struct target_in6_addr sin6_addr;
|
||||
uint32_t sin6_scope_id;
|
||||
};
|
||||
|
||||
struct target_in6_addrlifetime {
|
||||
target_freebsd_time_t ia6t_expire;
|
||||
target_freebsd_time_t ia6t_preferred;
|
||||
u_int32_t ia6t_vltime;
|
||||
u_int32_t ia6t_pltime;
|
||||
};
|
||||
|
||||
struct target_in6_ifstat {
|
||||
uint64_t ifs6_in_receive;
|
||||
uint64_t ifs6_in_hdrerr;
|
||||
uint64_t ifs6_in_toobig;
|
||||
uint64_t ifs6_in_noroute;
|
||||
uint64_t ifs6_in_addrerr;
|
||||
uint64_t ifs6_in_protounknown;
|
||||
|
||||
uint64_t ifs6_in_truncated;
|
||||
uint64_t ifs6_in_discard;
|
||||
|
||||
uint64_t ifs6_in_deliver;
|
||||
|
||||
uint64_t ifs6_out_forward;
|
||||
|
||||
uint64_t ifs6_out_request;
|
||||
|
||||
uint64_t ifs6_out_discard;
|
||||
uint64_t ifs6_out_fragok;
|
||||
uint64_t ifs6_out_fragfail;
|
||||
uint64_t ifs6_out_fragcreat;
|
||||
|
||||
uint64_t ifs6_reass_reqd;
|
||||
|
||||
uint64_t ifs6_reass_ok;
|
||||
|
||||
uint64_t ifs6_reass_fail;
|
||||
|
||||
uint64_t ifs6_in_mcast;
|
||||
uint64_t ifs6_out_mcast;
|
||||
};
|
||||
|
||||
struct target_icmp6_ifstat {
|
||||
uint64_t ifs6_in_msg;
|
||||
uint64_t ifs6_in_error;
|
||||
uint64_t ifs6_in_dstunreach;
|
||||
uint64_t ifs6_in_adminprohib;
|
||||
uint64_t ifs6_in_timeexceed;
|
||||
uint64_t ifs6_in_paramprob;
|
||||
uint64_t ifs6_in_pkttoobig;
|
||||
uint64_t ifs6_in_echo;
|
||||
uint64_t ifs6_in_echoreply;
|
||||
uint64_t ifs6_in_routersolicit;
|
||||
uint64_t ifs6_in_routeradvert;
|
||||
uint64_t ifs6_in_neighborsolicit;
|
||||
uint64_t ifs6_in_neighboradvert;
|
||||
uint64_t ifs6_in_redirect;
|
||||
uint64_t ifs6_in_mldquery;
|
||||
uint64_t ifs6_in_mldreport;
|
||||
uint64_t ifs6_in_mlddone;
|
||||
|
||||
uint64_t ifs6_out_msg;
|
||||
uint64_t ifs6_out_error;
|
||||
uint64_t ifs6_out_dstunreach;
|
||||
uint64_t ifs6_out_adminprohib;
|
||||
uint64_t ifs6_out_timeexceed;
|
||||
uint64_t ifs6_out_paramprob;
|
||||
uint64_t ifs6_out_pkttoobig;
|
||||
uint64_t ifs6_out_echo;
|
||||
uint64_t ifs6_out_echoreply;
|
||||
uint64_t ifs6_out_routersolicit;
|
||||
uint64_t ifs6_out_routeradvert;
|
||||
uint64_t ifs6_out_neighborsolicit;
|
||||
uint64_t ifs6_out_neighboradvert;
|
||||
uint64_t ifs6_out_redirect;
|
||||
uint64_t ifs6_out_mldquery;
|
||||
uint64_t ifs6_out_mldreport;
|
||||
uint64_t ifs6_out_mlddone;
|
||||
};
|
||||
|
||||
#ifndef TARGET_IFNAMSIZ
|
||||
#define TARGET_IFNAMSIZ 16
|
||||
#endif
|
||||
|
||||
struct target_in6_ifreq {
|
||||
char ifr_name[TARGET_IFNAMSIZ];
|
||||
union {
|
||||
struct target_sockaddr_in6 ifru_addr;
|
||||
struct target_sockaddr_in6 ifru_dstaddr;
|
||||
int ifru_flags;
|
||||
int ifru_flags6;
|
||||
int ifru_metric;
|
||||
abi_ulong ifru_data;
|
||||
struct target_in6_addrlifetime ifru_lifetime;
|
||||
struct target_in6_ifstat ifru_stat;
|
||||
struct target_icmp6_ifstat ifru_icmp6stat;
|
||||
u_int32_t ifru_scope_id[16];
|
||||
} ifr_ifru;
|
||||
};
|
||||
|
||||
/* netinet6/nd6.h */
|
||||
struct target_nd_ifinfo {
|
||||
uint32_t linkmtu;
|
||||
uint32_t maxmtu;
|
||||
uint32_t basereachable;
|
||||
uint32_t reachable;
|
||||
uint32_t retrans;
|
||||
uint32_t flags;
|
||||
int32_t recalctm;
|
||||
uint8_t chlim;
|
||||
uint8_t initialized;
|
||||
uint8_t randomseed0[8];
|
||||
uint8_t randomseed1[8];
|
||||
uint8_t randomid[8];
|
||||
};
|
||||
|
||||
/* netinet6/nd6.h */
|
||||
struct target_in6_ndireq {
|
||||
char ifname[TARGET_IFNAMSIZ];
|
||||
struct target_nd_ifinfo ndi;
|
||||
};
|
||||
|
||||
struct target_in6_ndifreq {
|
||||
char ifname[IFNAMSIZ];
|
||||
abi_ulong ifindex;
|
||||
};
|
||||
|
||||
|
||||
#define TARGET_SIOCGIFDSTADDR_IN6 TARGET_IOWR('i', 34, struct target_in6_ifreq)
|
||||
#define TARGET_SIOCGIFNETMASK_IN6 TARGET_IOWR('i', 37, struct target_in6_ifreq)
|
||||
|
||||
#define TARGET_SIOCDIFADDR_IN6 TARGET_IOW('i', 25, struct target_in6_ifreq)
|
||||
/* NOT YET
|
||||
#define TARGET_OSIOCAIFADDR_IN6 TARGET_IOW('i', 26, struct target_oin6_aliasreq)
|
||||
#define TARGET_SIOCAIFADDR_IN6 TARGET_IOW('i', 27, struct target_in6_aliasreq)
|
||||
|
||||
#define TARGET_SIOCSIFPHYADDR_IN6 TARGET_IOW('i', 70, struct target_in6_aliasreq)
|
||||
*/
|
||||
#define TARGET_SIOCGIFPSRCADDR_IN6 TARGET_IOWR('i', 71, struct target_in6_ifreq)
|
||||
#define TARGET_SIOCGIFPDSTADDR_IN6 TARGET_IOWR('i', 72, struct target_in6_ifreq)
|
||||
|
||||
#define TARGET_SIOCGIFAFLAG_IN6 TARGET_IOWR('i', 73, struct target_in6_ifreq)
|
||||
|
||||
/* NOT YET
|
||||
#define TARGET_SIOCGDRLST_IN6 TARGET_IOWR('i', 74, struct target_in6_drlist)
|
||||
*/
|
||||
|
||||
#define TARGET_SIOCGIFINFO_IN6 TARGET_IOWR('i', 108, struct target_in6_ndireq)
|
||||
#define TARGET_SIOCSIFINFO_IN6 TARGET_IOWR('i', 109, struct target_in6_ndireq)
|
||||
|
||||
#define TARGET_SIOCSNDFLUSH_IN6 TARGET_IOWR('i', 77, struct target_in6_ifreq)
|
||||
/* NOT YET
|
||||
#define TARGET_SIOCGNBRINFO_IN6 TARGET_IOWR('i', 78, struct target_in6_nbrinfo)
|
||||
*/
|
||||
#define TARGET_SIOCSPFXFLUSH_IN6 TARGET_IOWR('i', 79, struct target_in6_ifreq)
|
||||
#define TARGET_SIOCSRTRFLUSH_IN6 TARGET_IOWR('i', 80, struct target_in6_ifreq)
|
||||
|
||||
#define TARGET_SIOCGIFALIFETIME_IN6 TARGET_IOWR('i', 81, struct target_in6_ifreq)
|
||||
#define TARGET_SIOCSIFALIFETIME_IN6 TARGET_IOWR('i', 82, struct target_in6_ifreq)
|
||||
#define TARGET_SIOCGIFSTAT_IN6 TARGET_IOWR('i', 83, struct target_in6_ifreq)
|
||||
#define TARGET_SIOCGIFSTAT_ICMP6 TARGET_IOWR('i', 84, struct target_in6_ifreq)
|
||||
|
||||
#define TARGET_SIOCSDEFIFACE_IN6 TARGET_IOWR('i', 85, struct target_in6_ndifreq)
|
||||
#define TARGET_SIOCGDEFIFACE_IN6 TARGET_IOWR('i', 86, struct target_in6_ndifreq)
|
||||
|
||||
#define TARGET_SIOCSIFINFO_FLAGS TARGET_IOWR('i', 87, struct target_in6_ndireq)
|
||||
|
||||
#define TARGET_SIOCSSCOPE6 TARGET_IOW('i', 88, struct target_in6_ifreq)
|
||||
#define TARGET_SIOCGSCOPE6 TARGET_IOWR('i', 89, struct target_in6_ifreq)
|
||||
#define TARGET_SIOCGSCOPE6DEF TARGET_IOWR('i', 90, struct target_in6_ifreq)
|
||||
|
||||
/* NOT YET
|
||||
#define TARGET_SIOCSIFPREFIX_IN6 TARGET_IOW('i', 100, struct target_in6_prefixreq)
|
||||
#define TARGET_SIOCGIFPREFIX_IN6 TARGET_IOWR('i', 101, struct target_in6_prefixreq)
|
||||
#define TARGET_SIOCDIFPREFIX_IN6 TARGET_IOW('i', 102, struct target_in6_prefixreq)
|
||||
#define TARGET_SIOCAIFPREFIX_IN6 TARGET_IOW('i', 103, struct target_in6_rrenumreq)
|
||||
#define TARGET_SIOCCIFPREFIX_IN6 TARGET_IOW('i', 104, struct target_in6_rrenumreq)
|
||||
#define TARGET_SIOCSGIFPREFIX_IN6 TARGET_IOW('i', 105, struct target_in6_rrenumreq)
|
||||
|
||||
#define TARGET_SIOCGETSGCNT_IN6 TARGET_IOWR('u', 106, struct target_sioc_sg_req6)
|
||||
#define TARGET_SIOCGETMIFCNT_IN6 TARGET_IOWR('u', 107, struct target_sioc_mif_req6)
|
||||
|
||||
#define TARGET_SIOCAADDRCTL_POLICY TARGET_IOW('u', 108, struct target_in6_addrpolicy)
|
||||
#define TARGET_SIOCDADDRCTL_POLICY TARGET_IOW('u', 109, struct target_in6_addrpolicy)
|
||||
*/
|
||||
|
||||
#endif /* !_IOCTL_IN6_VAR_H_ */
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* FreeBSD ioccom definitions for ioctl(2) emulation
|
||||
*
|
||||
* 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 _IOCTL_IOCCOM_H_
|
||||
#define _IOCTL_IOCCOM_H_
|
||||
/*
|
||||
* Ioctl's have the command encoded in the lower word, and the size of
|
||||
* any in or out parameters in the upper word. The high 3 bits of the
|
||||
* upper word are used to encode the in/out status of the parameter.
|
||||
*/
|
||||
/* number of bits for ioctl size */
|
||||
#define TARGET_IOCPARM_SHIFT 13
|
||||
|
||||
/* parameter length mask */
|
||||
#define TARGET_IOCPARM_MASK ((1 << TARGET_IOCPARM_SHIFT) - 1)
|
||||
|
||||
#define TARGET_IOCPARM_LEN(x) (((x) >> 16) & TARGET_IOCPARM_MASK)
|
||||
#define TARGET_IOCBASECMD(x) ((x) & ~(TARGET_IOCPARM_MASK << 16))
|
||||
#define TARGET_IOCGROUP(x) (((x) >> 8) & 0xff)
|
||||
|
||||
#define TARGET_IOCPARM_MAX (1 << TARGET_IOCPARM_SHIFT) /* max size of ioctl */
|
||||
#define TARGET_IOC_VOID 0x20000000 /* no parameters */
|
||||
#define TARGET_IOC_OUT 0x40000000 /* copy out parameters */
|
||||
#define TARGET_IOC_IN 0x80000000 /* copy in parameters */
|
||||
#define TARGET_IOC_INOUT (TARGET_IOC_IN|TARGET_IOC_OUT)
|
||||
#define TARGET_IOC_DIRMASK (TARGET_IOC_VOID|TARGET_IOC_OUT|TARGET_IOC_IN)
|
||||
|
||||
#define TARGET_IOC(inout, group, num, len) ((abi_ulong) \
|
||||
((inout) | (((len) & TARGET_IOCPARM_MASK) << 16) | ((group) << 8) \
|
||||
| (num)))
|
||||
#define TARGET_IO(g, n) TARGET_IOC(IOC_VOID, (g), (n), 0)
|
||||
#define TARGET_IOWINT(g, n) TARGET_IOC(IOC_VOID, (g), (n), sizeof(int))
|
||||
#define TARGET_IOR(g, n, t) TARGET_IOC(IOC_OUT, (g), (n), sizeof(t))
|
||||
#define TARGET_IOW(g, n, t) TARGET_IOC(IOC_IN, (g), (n), sizeof(t))
|
||||
/* this should be _IORW, but stdio got there first */
|
||||
#define TARGET_IOWR(g, n, t) TARGET_IOC(IOC_INOUT, (g), (n), sizeof(t))
|
||||
|
||||
#endif /* !_IOCTL_IOCCOM_H_ */
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* FreeBSD sockio.h definitions for ioctl(2) emulation
|
||||
*
|
||||
* Copyright (c) 2015 Stacey D. Son
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 _OS_IOCTL_SOCKIO_H_
|
||||
#define _OS_IOCTL_SOCKIO_H_
|
||||
|
||||
/* See sys/sockio.h */
|
||||
#define TARGET_SIOCSHIWAT TARGET_IOW('s', 0, int32_t)
|
||||
#define TARGET_SIOCGHIWAT TARGET_IOR('s', 1, int32_t)
|
||||
#define TARGET_SIOCSLOWAT TARGET_IOW('s', 2, int32_t)
|
||||
#define TARGET_SIOCGLOWAT TARGET_IOR('s', 3, int32_t)
|
||||
#define TARGET_SIOCATMARK TARGET_IOR('s', 7, int32_t)
|
||||
#define TARGET_SIOCSPGRP TARGET_IOW('s', 8, int32_t)
|
||||
#define TARGET_SIOCGPGRP TARGET_IOR('s', 9, int32_t)
|
||||
|
||||
/* See net/if.h */
|
||||
struct target_ifreq_buffer {
|
||||
abi_ulong length;
|
||||
abi_ulong buffer;
|
||||
};
|
||||
|
||||
#define TARGET_IFNAMSIZ 16
|
||||
|
||||
struct target_ifreq {
|
||||
char ifr_name[TARGET_IFNAMSIZ];
|
||||
union {
|
||||
struct target_sockaddr ifru_addr;
|
||||
struct target_sockaddr ifru_dstaddr;
|
||||
struct target_sockaddr ifru_broadaddr;
|
||||
struct target_ifreq_buffer ifru_buffer;
|
||||
int16_t ifru_flags[2];
|
||||
int16_t ifru_index;
|
||||
int32_t ifru_jid;
|
||||
int32_t ifru_metric;
|
||||
int32_t ifru_mtu;
|
||||
int32_t ifru_phys;
|
||||
int32_t ifru_media;
|
||||
abi_ulong ifru_data;
|
||||
int32_t ifru_cap[2];
|
||||
uint32_t ifru_fib;
|
||||
} ifr_ifru;
|
||||
};
|
||||
|
||||
|
||||
#define TARGET_SIOCSIFADDR TARGET_IOW('i', 12, struct target_ifreq)
|
||||
#define TARGET_SIOCGIFADDR TARGET_IOWR('i', 33, struct target_ifreq)
|
||||
#define TARGET_SIOCSIFDSTADDR TARGET_IOW('i', 14, struct target_ifreq)
|
||||
#define TARGET_SIOCGIFDSTADDR TARGET_IOWR('i', 34, struct target_ifreq)
|
||||
#define TARGET_SIOCSIFFLAGS TARGET_IOW('i', 16, struct target_ifreq)
|
||||
#define TARGET_SIOCGIFFLAGS TARGET_IOWR('i', 17, struct target_ifreq)
|
||||
#define TARGET_SIOCGIFBRDADDR TARGET_IOWR('i', 35, struct target_ifreq)
|
||||
#define TARGET_SIOCSIFBRDADDR TARGET_IOW('i', 19, struct target_ifreq)
|
||||
#define TARGET_SIOCGIFNETMASK TARGET_IOWR('i', 37, struct target_ifreq)
|
||||
#define TARGET_SIOCSIFNETMASK TARGET_IOW('i', 22, struct target_ifreq)
|
||||
#define TARGET_SIOCGIFMETRIC TARGET_IOWR('i', 23, struct target_ifreq)
|
||||
#define TARGET_SIOCSIFMETRIC TARGET_IOW('i', 24, struct target_ifreq)
|
||||
#define TARGET_SIOCDIFADDR TARGET_IOW('i', 25, struct target_ifreq)
|
||||
#define TARGET_SIOCSIFCAP TARGET_IOW('i', 30, struct target_ifreq)
|
||||
#define TARGET_SIOCGIFCAP TARGET_IOWR('i', 31, struct target_ifreq)
|
||||
#define TARGET_SIOCGIFINDEX TARGET_IOWR('i', 32, struct target_ifreq)
|
||||
#define TARGET_SIOCGIFMAC TARGET_IOWR('i', 38, struct target_ifreq)
|
||||
#define TARGET_SIOCSIFMAC TARGET_IOW('i', 39, struct target_ifreq)
|
||||
#define TARGET_SIOCSIFNAME TARGET_IOW('i', 40, struct target_ifreq)
|
||||
#define TARGET_SIOCSIFDESCR TARGET_IOW('i', 41, struct target_ifreq)
|
||||
#define TARGET_SIOCGIFDESCR TARGET_IOWR('i', 42, struct target_ifreq)
|
||||
#define TARGET_SIOCADDMULTI TARGET_IOW('i', 49, struct target_ifreq)
|
||||
#define TARGET_SIOCDELMULTI TARGET_IOW('i', 50, struct target_ifreq)
|
||||
#define TARGET_SIOCGIFMTU TARGET_IOWR('i', 51, struct target_ifreq)
|
||||
#define TARGET_SIOCSIFMTU TARGET_IOW('i', 52, struct target_ifreq)
|
||||
#define TARGET_SIOCGIFPHYS TARGET_IOWR('i', 53, struct target_ifreq)
|
||||
#define TARGET_SIOCSIFPHYS TARGET_IOW('i', 54, struct target_ifreq)
|
||||
#define TARGET_SIOCSIFMEDIA TARGET_IOWR('i', 55, struct target_ifreq)
|
||||
#define TARGET_SIOCSIFGENERIC TARGET_IOW('i', 57, struct target_ifreq)
|
||||
#define TARGET_SIOCGIFGENERIC TARGET_IOWR('i', 58, struct target_ifreq)
|
||||
#define TARGET_SIOCSIFLLADDR TARGET_IOW('i', 60, struct target_ifreq)
|
||||
#define TARGET_SIOCGIFPSRCADDR TARGET_IOWR('i', 71, struct target_ifreq)
|
||||
#define TARGET_SIOCGIFPDSTADDR TARGET_IOWR('i', 72, struct target_ifreq)
|
||||
#define TARGET_SIOCDIFPHYADDR TARGET_IOW('i', 73, struct target_ifreq)
|
||||
#define TARGET_SIOCGPRIVATE_0 TARGET_IOWR('i', 80, struct target_ifreq)
|
||||
#define TARGET_SIOCGPRIVATE_1 TARGET_IOWR('i', 81, struct target_ifreq)
|
||||
#define TARGET_SIOCSIFVNET TARGET_IOWR('i', 90, struct target_ifreq)
|
||||
#define TARGET_SIOCSIFRVNET TARGET_IOWR('i', 91, struct target_ifreq)
|
||||
#define TARGET_SIOCGIFFIB TARGET_IOWR('i', 92, struct target_ifreq)
|
||||
#define TARGET_SIOCSIFFIB TARGET_IOW('i', 93, struct target_ifreq)
|
||||
#define TARGET_SIOCGTUNFIB TARGET_IOWR('i', 94, struct target_ifreq)
|
||||
#define TARGET_SIOCIFCREATE TARGET_IOWR('i', 122, struct target_ifreq)
|
||||
#define TARGET_SIOCIFCREATE2 TARGET_IOWR('i', 124, struct target_ifreq)
|
||||
#define TARGET_SIOCIFDESTROY TARGET_IOW('i', 121, struct target_ifreq)
|
||||
|
||||
/* net/if_gre.h */
|
||||
#define TARGET_GREGKEY TARGET_IOWR('i', 107, struct target_ifreq)
|
||||
#define TARGET_GREGOPTS TARGET_IOWR('i', 109, struct target_ifreq)
|
||||
|
||||
/* net/if_gif.h */
|
||||
#define TARGET_GIFGOPTS TARGET_IOWR('i', 150, struct target_ifreq)
|
||||
|
||||
/* netinet/ip_carp.h */
|
||||
#define TARGET_SIOCGVH TARGET_IOWR('i', 246, struct target_ifreq)
|
||||
|
||||
/* netinet/ip_carp.h */
|
||||
#define TARGET_SIOCGVH TARGET_IOWR('i', 246, struct target_ifreq)
|
||||
|
||||
/* net/if_pfsync.h */
|
||||
#define TARGET_SIOCGETPFSYNC TARGET_IOWR('i', 248, struct target_ifreq)
|
||||
|
||||
|
||||
/* See net/if.h */
|
||||
struct target_ifconf {
|
||||
int32_t ifc_len;
|
||||
union {
|
||||
abi_ulong ifcu_buf;
|
||||
abi_ulong ifcu_reg;
|
||||
} ifc_ifcu;
|
||||
};
|
||||
|
||||
#define TARGET_SIOCGIFCONF TARGET_IOWR('i', 36, struct target_ifconf)
|
||||
|
||||
/* See net/if.h */
|
||||
struct target_ifdrv {
|
||||
char ifd_name[TARGET_IFNAMSIZ];
|
||||
abi_ulong ifd_cmd;
|
||||
abi_ulong ifd_len;
|
||||
abi_ulong ifd_data;
|
||||
};
|
||||
|
||||
#define TARGET_SIOCSDRVSPEC TARGET_IOW('i', 123, struct target_ifdrv)
|
||||
#define TARGET_SIOCGDRVSPEC TARGET_IOWR('i', 123, struct target_ifdrv)
|
||||
|
||||
/* See net/if.h */
|
||||
struct target_ifg_req {
|
||||
union {
|
||||
char ifgrqu_group[TARGET_IFNAMSIZ];
|
||||
char ifgrqu_member[TARGET_IFNAMSIZ];
|
||||
} ifgrq_ifgrqu;
|
||||
};
|
||||
|
||||
struct target_ifgroupreq {
|
||||
char ifgr_name[TARGET_IFNAMSIZ];
|
||||
uint32_t ifgr_len;
|
||||
union {
|
||||
char ifgru_group[TARGET_IFNAMSIZ];
|
||||
abi_ulong ifgru_groups;
|
||||
} ifgr_ifgru;
|
||||
};
|
||||
|
||||
#define TARGET_SIOCGIFGROUP TARGET_IOWR('i', 136, struct target_ifgroupreq)
|
||||
|
||||
struct target_ifmediareq {
|
||||
char ifm_name[TARGET_IFNAMSIZ];
|
||||
int32_t ifm_current;
|
||||
int32_t ifm_mask;
|
||||
int32_t ifm_status;
|
||||
int32_t ifm_active;
|
||||
int32_t ifm_count;
|
||||
abi_ulong ifm_ulist;
|
||||
};
|
||||
|
||||
#define TARGET_SIOCGIFMEDIA TARGET_IOWR('i', 56, struct target_ifmediareq)
|
||||
#define TARGET_SIOCGIFXMEDIA TARGET_IOWR('i', 139, struct target_ifmediareq)
|
||||
|
||||
#define TARGET_IFSTATMAX 800
|
||||
struct target_ifstat {
|
||||
char ifs_name[TARGET_IFNAMSIZ];
|
||||
char ascii[TARGET_IFSTATMAX + 1];
|
||||
};
|
||||
|
||||
#define TARGET_SIOCGIFSTATUS TARGET_IOWR('i', 59, struct target_ifstat)
|
||||
|
||||
/* net80211/ieee80211_ioctl.h */
|
||||
struct target_ieee80211req {
|
||||
char i_name[TARGET_IFNAMSIZ];
|
||||
uint16_t i_type;
|
||||
int16_t i_val;
|
||||
uint16_t i_len;
|
||||
abi_ulong i_data;
|
||||
};
|
||||
|
||||
#define TARGET_SIOCG80211 TARGET_IOWR('i', 235, struct target_ieee80211req)
|
||||
|
||||
/* net/if_lagg.h */
|
||||
struct target_lacp_opreq {
|
||||
uint16_t actor_prio;
|
||||
uint8_t actor_mac[ETHER_ADDR_LEN];
|
||||
uint16_t actor_key;
|
||||
uint16_t actor_portprio;
|
||||
uint16_t actor_portno;
|
||||
uint8_t actor_state;
|
||||
uint16_t partner_prio;
|
||||
uint8_t partner_mac[ETHER_ADDR_LEN];
|
||||
uint16_t partner_key;
|
||||
uint16_t partner_portprio;
|
||||
uint16_t partner_portno;
|
||||
uint8_t partner_state;
|
||||
};
|
||||
|
||||
struct target_lagg_reqport {
|
||||
char rp_ifname[TARGET_IFNAMSIZ];
|
||||
char rp_portname[TARGET_IFNAMSIZ];
|
||||
u_int32_t rp_prio;
|
||||
u_int32_t rp_flags;
|
||||
union {
|
||||
struct target_lacp_opreq rpsc_lacp;
|
||||
} rp_psc;
|
||||
};
|
||||
#define TARGET_SIOCGLAGGPORT TARGET_IOWR('i', 140, struct target_lagg_reqport)
|
||||
|
||||
struct target_lagg_reqall {
|
||||
char ra_ifname[TARGET_IFNAMSIZ];
|
||||
uint32_t ra_proto;
|
||||
|
||||
abi_ulong ra_size;
|
||||
abi_ulong ra_port;
|
||||
int32_t ra_ports;
|
||||
union {
|
||||
struct target_lacp_opreq rpsc_lacp;
|
||||
} ra_psc;
|
||||
};
|
||||
#define TARGET_SIOCGLAGG TARGET_IOWR('i', 143, struct target_lagg_reqall)
|
||||
|
||||
struct target_lagg_reqflags {
|
||||
char rf_ifname[TARGET_IFNAMSIZ];
|
||||
uint32_t rf_flags;
|
||||
};
|
||||
#define TARGET_SIOCGLAGGFLAGS TARGET_IOWR('i', 145, struct target_lagg_reqflags)
|
||||
|
||||
struct target_lagg_reqopts {
|
||||
char ro_ifname[IFNAMSIZ];
|
||||
int32_t ro_opts;
|
||||
uint32_t ro_count;
|
||||
uint32_t ro_active;
|
||||
uint32_t ro_flapping;
|
||||
int32_t ro_flowid_shift;
|
||||
};
|
||||
#define TARGET_SIOCGLAGGOPTS TARGET_IOWR('i', 152, struct target_lagg_reqopts)
|
||||
|
||||
#endif /* _OS_IOCTL_SOCKIO_H_ */
|
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
* FreeBSD ttycom definitions for ioctl(2) emulation
|
||||
*
|
||||
* 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 _IOCTL_TTYCOM_H_
|
||||
#define _IOCTL_TTYCOM_H_
|
||||
|
||||
#include "os-ioctl-ioccom.h"
|
||||
|
||||
/* From sys/ttycom.h and sys/_termios.h */
|
||||
|
||||
#define TARGET_VEOF 0 /* ICANON */
|
||||
#define TARGET_VEOL 1 /* ICANON */
|
||||
#define TARGET_VEOL2 2 /* ICANON together with IEXTEN */
|
||||
#define TARGET_VERASE 3 /* ICANON */
|
||||
#define TARGET_VWERASE 4 /* ICANON together with IEXTEN */
|
||||
#define TARGET_VKILL 5 /* ICANON */
|
||||
#define TARGET_VREPRINT 6 /* ICANON together with IEXTEN */
|
||||
#define TARGET_VERASE2 7 /* ICANON */
|
||||
#define TARGET_VINTR 8 /* ISIG */
|
||||
#define TARGET_VQUIT 9 /* ISIG */
|
||||
#define TARGET_VSUSP 10 /* ISIG */
|
||||
#define TARGET_VDSUSP 11 /* ISIG together with IEXTEN */
|
||||
#define TARGET_VSTART 12 /* IXON, IXOFF */
|
||||
#define TARGET_VSTOP 13 /* IXON, IXOFF */
|
||||
#define TARGET_VLNEXT 14 /* IEXTEN */
|
||||
#define TARGET_VDISCARD 15 /* IEXTEN */
|
||||
#define TARGET_VMIN 16 /* !ICANON */
|
||||
#define TARGET_VTIME 17 /* !ICANON */
|
||||
#define TARGET_VSTATUS 18 /* ICANON together with IEXTEN */
|
||||
/* 19 spare 2 */
|
||||
#define TARGET_NCCS 20
|
||||
|
||||
/*
|
||||
* Input flags - software input processing
|
||||
*/
|
||||
#define TARGET_IGNBRK 0x00000001 /* ignore BREAK condition */
|
||||
#define TARGET_BRKINT 0x00000002 /* map BREAK to SIGINTR */
|
||||
#define TARGET_IGNPAR 0x00000004 /* ignore (discard) parity errors */
|
||||
#define TARGET_PARMRK 0x00000008 /* mark parity and framing errors */
|
||||
#define TARGET_INPCK 0x00000010 /* enable checking of parity errors */
|
||||
#define TARGET_ISTRIP 0x00000020 /* strip 8th bit off chars */
|
||||
#define TARGET_INLCR 0x00000040 /* map NL into CR */
|
||||
#define TARGET_IGNCR 0x00000080 /* ignore CR */
|
||||
#define TARGET_ICRNL 0x00000100 /* map CR to NL (ala CRMOD) */
|
||||
#define TARGET_IXON 0x00000200 /* enable output flow control */
|
||||
#define TARGET_IXOFF 0x00000400 /* enable input flow control */
|
||||
#define TARGET_IXANY 0x00000800 /* any char will restart after stop */
|
||||
#define TARGET_IMAXBEL 0x00002000 /* ring bell on input queue full */
|
||||
|
||||
/*
|
||||
* Output flags - software output processing
|
||||
*/
|
||||
#define TARGET_OPOST 0x00000001 /* enable following output processing */
|
||||
#define TARGET_ONLCR 0x00000002 /* map NL to CR-NL (ala CRMOD) */
|
||||
#define TARGET_TABDLY 0x00000004 /* tab delay mask */
|
||||
#define TARGET_TAB0 0x00000000 /* no tab delay and expansion */
|
||||
#define TARGET_TAB3 0x00000004 /* expand tabs to spaces */
|
||||
#define TARGET_ONOEOT 0x00000008 /* discard EOT's (^D) on output) */
|
||||
#define TARGET_OCRNL 0x00000010 /* map CR to NL on output */
|
||||
#define TARGET_ONOCR 0x00000020 /* no CR output at column 0 */
|
||||
#define TARGET_ONLRET 0x00000040 /* NL performs CR function */
|
||||
|
||||
/*
|
||||
* Control flags - hardware control of terminal
|
||||
*/
|
||||
#define TARGET_CIGNORE 0x00000001 /* ignore control flags */
|
||||
#define TARGET_CSIZE 0x00000300 /* character size mask */
|
||||
#define TARGET_CS5 0x00000000 /* 5 bits (pseudo) */
|
||||
#define TARGET_CS6 0x00000100 /* 6 bits */
|
||||
#define TARGET_CS7 0x00000200 /* 7 bits */
|
||||
#define TARGET_CS8 0x00000300 /* 8 bits */
|
||||
#define TARGET_CSTOPB 0x00000400 /* send 2 stop bits */
|
||||
#define TARGET_CREAD 0x00000800 /* enable receiver */
|
||||
#define TARGET_PARENB 0x00001000 /* parity enable */
|
||||
#define TARGET_PARODD 0x00002000 /* odd parity, else even */
|
||||
#define TARGET_HUPCL 0x00004000 /* hang up on last close */
|
||||
#define TARGET_CLOCAL 0x00008000 /* ignore modem status lines */
|
||||
#define TARGET_CCTS_OFLOW 0x00010000 /* CTS flow control of output */
|
||||
#define TARGET_CRTSCTS (TARGET_CCTS_OFLOW | TARGET_CRTS_IFLOW)
|
||||
#define TARGET_CRTS_IFLOW 0x00020000 /* RTS flow control of input */
|
||||
#define TARGET_CDTR_IFLOW 0x00040000 /* DTR flow control of input */
|
||||
#define TARGET_CDSR_OFLOW 0x00080000 /* DSR flow control of output */
|
||||
#define TARGET_CCAR_OFLOW 0x00100000 /* DCD flow control of output */
|
||||
|
||||
/*
|
||||
* "Local" flags - dumping ground for other state
|
||||
*/
|
||||
#define TARGET_ECHOKE 0x00000001 /* visual erase for line kill */
|
||||
#define TARGET_ECHOE 0x00000002 /* visually erase chars */
|
||||
#define TARGET_ECHOK 0x00000004 /* echo NL after line kill */
|
||||
#define TARGET_ECHO 0x00000008 /* enable echoing */
|
||||
#define TARGET_ECHONL 0x00000010 /* echo NL even if ECHO is off */
|
||||
#define TARGET_ECHOPRT 0x00000020 /* visual erase mode for hardcopy */
|
||||
#define TARGET_ECHOCTL 0x00000040 /* echo control chars as ^(Char) */
|
||||
#define TARGET_ISIG 0x00000080 /* enable signals INTR, QUIT, [D]SUSP */
|
||||
#define TARGET_ICANON 0x00000100 /* canonicalize input lines */
|
||||
#define TARGET_ALTWERASE 0x00000200 /* use alternate WERASE algorithm */
|
||||
#define TARGET_IEXTEN 0x00000400 /* enable DISCARD and LNEXT */
|
||||
#define TARGET_EXTPROC 0x00000800 /* external processing */
|
||||
#define TARGET_TOSTOP 0x00400000 /* stop background jobs from output */
|
||||
#define TARGET_FLUSHO 0x00800000 /* output being flushed (state) */
|
||||
#define TARGET_NOKERNINFO 0x02000000 /* no kernel output from VSTATUS */
|
||||
#define TARGET_PENDIN 0x20000000 /* XXX retype pending input (state) */
|
||||
#define TARGET_NOFLSH 0x80000000 /* don't flush after interrupt */
|
||||
|
||||
struct target_termios {
|
||||
uint32_t c_iflag; /* input flags */
|
||||
uint32_t c_oflag; /* output flags */
|
||||
uint32_t c_cflag; /* control flags */
|
||||
uint32_t c_lflag; /* local flags */
|
||||
uint8_t c_cc[TARGET_NCCS]; /* control chars */
|
||||
uint32_t c_ispeed; /* input speed */
|
||||
uint32_t c_ospeed; /* output speed */
|
||||
};
|
||||
|
||||
|
||||
struct target_winsize {
|
||||
uint16_t ws_row; /* rows, in characters */
|
||||
uint16_t ws_col; /* columns, in characters */
|
||||
uint16_t ws_xpixel; /* horizontal size, pixels */
|
||||
uint16_t ws_ypixel; /* vertical size, pixels */
|
||||
};
|
||||
|
||||
/* 0-2 compat */
|
||||
/* 3-7 unused */
|
||||
/* 8-10 compat */
|
||||
/* 11-12 unused */
|
||||
#define TARGET_TIOCEXCL TARGET_IO('t', 13) /* set exclusive use of tty */
|
||||
#define TARGET_TIOCNXCL TARGET_IO('t', 14) /* reset exclusive use of tty */
|
||||
#define TARGET_TIOCGPTN TARGET_IOR('t', 15, int) /* Get pts number. */
|
||||
#define TARGET_TIOCFLUSH TARGET_IOW('t', 16, int) /* flush buffers */
|
||||
/* 17-18 compat */
|
||||
/* get termios struct */
|
||||
#define TARGET_TIOCGETA TARGET_IOR('t', 19, struct target_termios)
|
||||
/* set termios struct */
|
||||
#define TARGET_TIOCSETA TARGET_IOW('t', 20, struct target_termios)
|
||||
/* drain output, set */
|
||||
#define TARGET_TIOCSETAW TARGET_IOW('t', 21, struct target_termios)
|
||||
/* drn out, fls in, set */
|
||||
#define TARGET_TIOCSETAF TARGET_IOW('t', 22, struct target_termios)
|
||||
/* 23-25 unused */
|
||||
#define TARGET_TIOCGETD TARGET_IOR('t', 26, int) /* get line discipline */
|
||||
#define TARGET_TIOCSETD TARGET_IOW('t', 27, int) /* set line discipline */
|
||||
#define TARGET_TIOCPTMASTER TARGET_IO('t', 28) /* pts master validation */
|
||||
/* 29-85 unused */
|
||||
/* get ttywait timeout */
|
||||
#define TARGET_TIOCGDRAINWAIT TARGET_IOR('t', 86, int)
|
||||
/* set ttywait timeout */
|
||||
#define TARGET_TIOCSDRAINWAIT TARGET_IOW('t', 87, int)
|
||||
/* 88 unused */
|
||||
/* 89-91 conflicts: tun and tap */
|
||||
/* enable/get timestamp of last input event */
|
||||
#define TARGET_TIOCTIMESTAMP TARGET_IOR('t', 89, struct target_timeval)
|
||||
/* modem: get wait on close */
|
||||
#define TARGET_TIOCMGDTRWAIT TARGET_IOR('t', 90, int)
|
||||
/* modem: set wait on close */
|
||||
#define TARGET_TIOCMSDTRWAIT TARGET_IOW('t', 91, int)
|
||||
/* 92-93 tun and tap */
|
||||
/* 94-97 conflicts: tun and tap */
|
||||
/* wait till output drained */
|
||||
#define TARGET_TIOCDRAIN TARGET_IO('t', 94)
|
||||
/* pty: generate signal */
|
||||
#define TARGET_TIOCSIG TARGET_IOWINT('t', 95)
|
||||
/* pty: external processing */
|
||||
#define TARGET_TIOCEXT TARGET_IOW('t', 96, int)
|
||||
/* become controlling tty */
|
||||
#define TARGET_TIOCSCTTY TARGET_IO('t', 97)
|
||||
/* become virtual console */
|
||||
#define TARGET_TIOCCONS TARGET_IOW('t', 98, int)
|
||||
/* get session id */
|
||||
#define TARGET_TIOCGSID TARGET_IOR('t', 99, int)
|
||||
/* 100 unused */
|
||||
/* simulate ^T status message */
|
||||
#define TARGET_TIOCSTAT TARGET_IO('t', 101)
|
||||
/* pty: set/clr usr cntl mode */
|
||||
#define TARGET_TIOCUCNTL TARGET_IOW('t', 102, int)
|
||||
/* usr cntl op "n" */
|
||||
#define TARGET_TIOCCMD(n) TARGET_IO('u', n)
|
||||
/* set window size */
|
||||
#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct target_winsize)
|
||||
/* get window size */
|
||||
#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct target_winsize)
|
||||
/* 105 unused */
|
||||
/* get all modem bits */
|
||||
#define TARGET_TIOCMGET TARGET_IOR('t', 106, int)
|
||||
#define TARGET_TIOCM_LE 0001 /* line enable */
|
||||
#define TARGET_TIOCM_DTR 0002 /* data terminal ready */
|
||||
#define TARGET_TIOCM_RTS 0004 /* request to send */
|
||||
#define TARGET_TIOCM_ST 0010 /* secondary transmit */
|
||||
#define TARGET_TIOCM_SR 0020 /* secondary receive */
|
||||
#define TARGET_TIOCM_CTS 0040 /* clear to send */
|
||||
#define TARGET_TIOCM_DCD 0100 /* data carrier detect */
|
||||
#define TARGET_TIOCM_RI 0200 /* ring indicate */
|
||||
#define TARGET_TIOCM_DSR 0400 /* data set ready */
|
||||
#define TARGET_TIOCM_CD TARGET_TIOCM_DCD
|
||||
#define TARGET_TIOCM_CAR TARGET_TIOCM_DCD
|
||||
#define TARGET_TIOCM_RNG TARGET_TIOCM_RI
|
||||
#define TARGET_TIOCMBIC TARGET_IOW('t', 107, int) /* bic modem bits */
|
||||
#define TARGET_TIOCMBIS TARGET_IOW('t', 108, int) /* bis modem bits */
|
||||
#define TARGET_TIOCMSET TARGET_IOW('t', 109, int) /* set all modem bits */
|
||||
/* start output, like ^Q */
|
||||
#define TARGET_TIOCSTART TARGET_IO('t', 110)
|
||||
/* stop output, like ^S */
|
||||
#define TARGET_TIOCSTOP TARGET_IO('t', 111)
|
||||
/* pty: set/clear packet mode */
|
||||
#define TARGET_TIOCPKT TARGET_IOW('t', 112, int)
|
||||
#define TARGET_TIOCPKT_DATA 0x00 /* data packet */
|
||||
#define TARGET_TIOCPKT_FLUSHREAD 0x01 /* flush packet */
|
||||
#define TARGET_TIOCPKT_FLUSHWRITE 0x02 /* flush packet */
|
||||
#define TARGET_TIOCPKT_STOP 0x04 /* stop output */
|
||||
#define TARGET_TIOCPKT_START 0x08 /* start output */
|
||||
#define TARGET_TIOCPKT_NOSTOP 0x10 /* no more ^S, ^Q */
|
||||
#define TARGET_TIOCPKT_DOSTOP 0x20 /* now do ^S ^Q */
|
||||
#define TARGET_TIOCPKT_IOCTL 0x40 /* state change of pty
|
||||
driver */
|
||||
#define TARGET_TIOCNOTTY TARGET_IO('t', 113) /* void tty
|
||||
association */
|
||||
#define TARGET_TIOCSTI TARGET_IOW('t', 114, char) /* simulate
|
||||
terminal input */
|
||||
#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int) /* output queue size */
|
||||
/* 116-117 compat */
|
||||
#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int) /* set pgrp of tty */
|
||||
#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int) /* get pgrp of tty */
|
||||
#define TARGET_TIOCCDTR TARGET_IO('t', 120) /* clear data terminal
|
||||
ready */
|
||||
#define TARGET_TIOCSDTR TARGET_IO('t', 121) /* set data terminal
|
||||
ready */
|
||||
#define TARGET_TIOCCBRK TARGET_IO('t', 122) /* clear break bit */
|
||||
#define TARGET_TIOCSBRK TARGET_IO('t', 123) /* set break bit */
|
||||
/* 124-127 compat */
|
||||
|
||||
#define TARGET_TTYDISC 0 /* termios tty line
|
||||
discipline */
|
||||
#define TARGET_SLIPDISC 4 /* serial IP discipline */
|
||||
#define TARGET_PPPDISC 5 /* PPP discipline */
|
||||
#define TARGET_NETGRAPHDISC 6 /* Netgraph tty node
|
||||
discipline */
|
||||
#define TARGET_H4DISC 7 /* Netgraph Bluetooth H4
|
||||
discipline */
|
||||
|
||||
#endif /*! _IOCTL_TTYCOM_H_ */
|
|
@ -0,0 +1,97 @@
|
|||
|
||||
STRUCT_SPECIAL(termios)
|
||||
|
||||
STRUCT(winsize,
|
||||
TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT)
|
||||
|
||||
STRUCT(fiodgname_arg,
|
||||
TYPE_INT, TYPE_PTRVOID)
|
||||
|
||||
STRUCT(ifconf,
|
||||
TYPE_INT, TYPE_PTRVOID)
|
||||
|
||||
STRUCT(sockaddr,
|
||||
TYPE_SHORT, MK_ARRAY(TYPE_CHAR, 14))
|
||||
|
||||
STRUCT(_ifreq_buffer,
|
||||
TYPE_PTRVOID, TYPE_PTRVOID)
|
||||
|
||||
STRUCT(ifreq_char,
|
||||
MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_CHAR)
|
||||
|
||||
STRUCT(ifreq_short,
|
||||
MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_SHORT)
|
||||
|
||||
STRUCT(ifreq_int,
|
||||
MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_INT)
|
||||
|
||||
STRUCT(ifreq_ptr,
|
||||
MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_PTRVOID)
|
||||
|
||||
STRUCT(ifreq_cap,
|
||||
MK_ARRAY(TYPE_CHAR, IFNAMSIZ), MK_ARRAY(TYPE_INT, 2))
|
||||
|
||||
STRUCT(ifreq_sockaddr,
|
||||
MK_ARRAY(TYPE_CHAR, IFNAMSIZ), MK_STRUCT(STRUCT_sockaddr))
|
||||
|
||||
STRUCT(ifreq_buf,
|
||||
MK_ARRAY(TYPE_CHAR, IFNAMSIZ), MK_STRUCT(STRUCT__ifreq_buffer))
|
||||
|
||||
STRUCT(ifdrv,
|
||||
MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_PTRVOID, TYPE_PTRVOID, TYPE_PTRVOID)
|
||||
|
||||
STRUCT(ifgroupreq_ptr,
|
||||
MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_INT, TYPE_PTRVOID)
|
||||
|
||||
STRUCT(ifmediareq,
|
||||
MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
|
||||
TYPE_INT, TYPE_PTRVOID)
|
||||
|
||||
STRUCT(ifstat,
|
||||
MK_ARRAY(TYPE_CHAR, IFNAMSIZ), MK_ARRAY(TYPE_CHAR, IFSTATMAX))
|
||||
|
||||
STRUCT(ieee80211req,
|
||||
MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_INT, TYPE_INT, TYPE_INT, TYPE_PTRVOID)
|
||||
|
||||
STRUCT(lagg_reqport_lacp_opreq,
|
||||
MK_ARRAY(TYPE_CHAR, IFNAMSIZ), MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_INT,
|
||||
TYPE_INT,
|
||||
/* struct lacp_opreq */
|
||||
TYPE_SHORT, TYPE_CHAR, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_CHAR,
|
||||
TYPE_SHORT, TYPE_CHAR, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_CHAR)
|
||||
|
||||
STRUCT(lagg_reqall_lacp_opreq,
|
||||
MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_INT, TYPE_PTRVOID, TYPE_PTRVOID,
|
||||
TYPE_INT,
|
||||
/* struct lacp_opreq */
|
||||
TYPE_SHORT, TYPE_CHAR, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_CHAR,
|
||||
TYPE_SHORT, TYPE_CHAR, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_CHAR)
|
||||
|
||||
STRUCT(lagg_reqflags,
|
||||
MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_INT)
|
||||
|
||||
STRUCT(lagg_reqopts,
|
||||
MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
|
||||
TYPE_INT)
|
||||
|
||||
STRUCT(in6_ifreq_int,
|
||||
MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_INT)
|
||||
|
||||
STRUCT(in6_ifreq_ptr,
|
||||
MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_PTRVOID)
|
||||
|
||||
STRUCT(in6_ifreq_sockaddr_in6,
|
||||
MK_ARRAY(TYPE_CHAR, IFNAMSIZ),
|
||||
/* struct sockaddr_in6 */
|
||||
TYPE_CHAR, TYPE_CHAR, TYPE_SHORT, TYPE_INT, MK_ARRAY(TYPE_CHAR, 16),
|
||||
TYPE_INT)
|
||||
|
||||
STRUCT(in6_ndireq,
|
||||
MK_ARRAY(TYPE_CHAR, IFNAMSIZ),
|
||||
/* struct nd_ifinfo */
|
||||
TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
|
||||
TYPE_CHAR, TYPE_CHAR, MK_ARRAY(TYPE_CHAR, 8), MK_ARRAY(TYPE_CHAR, 8),
|
||||
MK_ARRAY(TYPE_CHAR, 8))
|
||||
|
||||
STRUCT(in6_ndifreq,
|
||||
MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_PTRVOID)
|
|
@ -0,0 +1,667 @@
|
|||
/*
|
||||
* miscellaneous FreeBSD system call shims
|
||||
*
|
||||
* Copyright (c) 2013-14 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 __OS_MISC_H_
|
||||
#define __OS_MISC_H_
|
||||
|
||||
#include <sys/cpuset.h>
|
||||
#include <sys/random.h>
|
||||
#include <sched.h>
|
||||
|
||||
int shm_open2(const char *path, int flags, mode_t mode, int shmflags,
|
||||
const char *);
|
||||
|
||||
/* sched_setparam(2) */
|
||||
static inline abi_long do_freebsd_sched_setparam(pid_t pid,
|
||||
abi_ulong target_sp_addr)
|
||||
{
|
||||
abi_long ret;
|
||||
struct sched_param host_sp;
|
||||
|
||||
ret = get_user_s32(host_sp.sched_priority, target_sp_addr);
|
||||
if (!is_error(ret)) {
|
||||
ret = get_errno(sched_setparam(pid, &host_sp));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* sched_get_param(2) */
|
||||
static inline abi_long do_freebsd_sched_getparam(pid_t pid,
|
||||
abi_ulong target_sp_addr)
|
||||
{
|
||||
abi_long ret;
|
||||
struct sched_param host_sp;
|
||||
|
||||
ret = get_errno(sched_getparam(pid, &host_sp));
|
||||
if (!is_error(ret)) {
|
||||
ret = put_user_s32(host_sp.sched_priority, target_sp_addr);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* sched_setscheduler(2) */
|
||||
static inline abi_long do_freebsd_sched_setscheduler(pid_t pid, int policy,
|
||||
abi_ulong target_sp_addr)
|
||||
{
|
||||
abi_long ret;
|
||||
struct sched_param host_sp;
|
||||
|
||||
ret = get_user_s32(host_sp.sched_priority, target_sp_addr);
|
||||
if (!is_error(ret)) {
|
||||
ret = get_errno(sched_setscheduler(pid, policy, &host_sp));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* sched_getscheduler(2) */
|
||||
static inline abi_long do_freebsd_sched_getscheduler(pid_t pid)
|
||||
{
|
||||
|
||||
return get_errno(sched_getscheduler(pid));
|
||||
}
|
||||
|
||||
/* sched_getscheduler(2) */
|
||||
static inline abi_long do_freebsd_sched_rr_get_interval(pid_t pid,
|
||||
abi_ulong target_ts_addr)
|
||||
{
|
||||
abi_long ret;
|
||||
struct timespec host_ts;
|
||||
|
||||
ret = get_errno(sched_rr_get_interval(pid, &host_ts));
|
||||
if (!is_error(ret)) {
|
||||
ret = h2t_freebsd_timespec(target_ts_addr, &host_ts);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* cpuset(2) */
|
||||
static inline abi_long do_freebsd_cpuset(abi_ulong target_cpuid)
|
||||
{
|
||||
abi_long ret;
|
||||
cpusetid_t setid;
|
||||
|
||||
ret = get_errno(cpuset(&setid));
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
return put_user_s32(setid, target_cpuid);
|
||||
}
|
||||
|
||||
#define target_to_host_cpuset_which(hp, t) { \
|
||||
(*hp) = t; \
|
||||
} while (0)
|
||||
|
||||
#define target_to_host_cpuset_level(hp, t) { \
|
||||
(*hp) = t; \
|
||||
} while (0)
|
||||
|
||||
/* cpuset_setid(2) */
|
||||
static inline abi_long do_freebsd_cpuset_setid(void *cpu_env, abi_long arg1,
|
||||
abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
|
||||
{
|
||||
id_t id; /* 64-bit value */
|
||||
cpusetid_t setid;
|
||||
cpuwhich_t which;
|
||||
|
||||
target_to_host_cpuset_which(&which, arg1);
|
||||
#if TARGET_ABI_BITS == 32
|
||||
/* See if we need to align the register pairs */
|
||||
if (regpairs_aligned(cpu_env)) {
|
||||
id = target_arg64(arg3, arg4);
|
||||
setid = arg5;
|
||||
} else {
|
||||
id = target_arg64(arg2, arg3);
|
||||
setid = arg4;
|
||||
}
|
||||
#else
|
||||
id = arg2;
|
||||
setid = arg3;
|
||||
#endif
|
||||
return get_errno(cpuset_setid(which, id, setid));
|
||||
}
|
||||
|
||||
/* cpuset_getid(2) */
|
||||
static inline abi_long do_freebsd_cpuset_getid(abi_long arg1, abi_ulong arg2,
|
||||
abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
|
||||
{
|
||||
abi_long ret;
|
||||
id_t id; /* 64-bit value */
|
||||
cpusetid_t setid;
|
||||
cpuwhich_t which;
|
||||
cpulevel_t level;
|
||||
abi_ulong target_setid;
|
||||
|
||||
target_to_host_cpuset_which(&which, arg1)
|
||||
;
|
||||
target_to_host_cpuset_level(&level, arg2);
|
||||
#if TARGET_ABI_BITS == 32
|
||||
id = target_arg64(arg3, arg4);
|
||||
target_setid = arg5;
|
||||
#else
|
||||
id = arg3;
|
||||
target_setid = arg4;
|
||||
#endif
|
||||
ret = get_errno(cpuset_getid(level, which, id, &setid));
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
return put_user_s32(setid, target_setid);
|
||||
}
|
||||
|
||||
static abi_ulong copy_from_user_cpuset_mask(cpuset_t *mask,
|
||||
abi_ulong target_mask_addr)
|
||||
{
|
||||
int i, j, k;
|
||||
abi_ulong b, *target_mask;
|
||||
|
||||
target_mask = lock_user(VERIFY_READ, target_mask_addr,
|
||||
(CPU_SETSIZE / 8), 1);
|
||||
if (target_mask == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
CPU_ZERO(mask);
|
||||
k = 0;
|
||||
for (i = 0; i < ((CPU_SETSIZE/8)/sizeof(abi_ulong)); i++) {
|
||||
__get_user(b, &target_mask[i]);
|
||||
for (j = 0; j < TARGET_ABI_BITS; j++) {
|
||||
if ((b >> j) & 1) {
|
||||
CPU_SET(k, mask);
|
||||
}
|
||||
k++;
|
||||
}
|
||||
}
|
||||
unlock_user(target_mask, target_mask_addr, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static abi_ulong copy_to_user_cpuset_mask(abi_ulong target_mask_addr,
|
||||
cpuset_t *mask)
|
||||
{
|
||||
int i, j, k;
|
||||
abi_ulong b, *target_mask;
|
||||
|
||||
target_mask = lock_user(VERIFY_WRITE, target_mask_addr,
|
||||
(CPU_SETSIZE / 8), 0);
|
||||
if (target_mask == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
k = 0;
|
||||
for (i = 0; i < ((CPU_SETSIZE/8)/sizeof(abi_ulong)); i++) {
|
||||
b = 0;
|
||||
for (j = 0; j < TARGET_ABI_BITS; j++) {
|
||||
b |= ((CPU_ISSET(k, mask) != 0) << j);
|
||||
k++;
|
||||
}
|
||||
__put_user(b, &target_mask[i]);
|
||||
}
|
||||
unlock_user(target_mask, target_mask_addr, (CPU_SETSIZE / 8));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* cpuset_getaffinity(2) */
|
||||
/* cpuset_getaffinity(cpulevel_t, cpuwhich_t, id_t, size_t, cpuset_t *); */
|
||||
static inline abi_long do_freebsd_cpuset_getaffinity(cpulevel_t level,
|
||||
cpuwhich_t which, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5,
|
||||
abi_ulong arg6)
|
||||
{
|
||||
cpuset_t mask;
|
||||
abi_long ret;
|
||||
id_t id; /* 64-bit */
|
||||
abi_ulong setsize, target_mask;
|
||||
|
||||
#if TARGET_ABI_BITS == 32
|
||||
id = (id_t)target_arg64(arg3, arg4);
|
||||
setsize = arg5;
|
||||
target_mask = arg6;
|
||||
#else
|
||||
id = (id_t)arg3;
|
||||
setsize = arg4;
|
||||
target_mask = arg5;
|
||||
#endif
|
||||
|
||||
ret = get_errno(cpuset_getaffinity(level, which, id, setsize, &mask));
|
||||
if (ret == 0) {
|
||||
ret = copy_to_user_cpuset_mask(target_mask, &mask);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* cpuset_setaffinity(2) */
|
||||
/* cpuset_setaffinity(cpulevel_t, cpuwhich_t, id_t, size_t, const cpuset_t *);*/
|
||||
static inline abi_long do_freebsd_cpuset_setaffinity(cpulevel_t level,
|
||||
cpuwhich_t which, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5,
|
||||
abi_ulong arg6)
|
||||
{
|
||||
cpuset_t mask;
|
||||
abi_long ret;
|
||||
id_t id; /* 64-bit */
|
||||
abi_ulong setsize, target_mask;
|
||||
|
||||
#if TARGET_ABI_BITS == 32
|
||||
id = (id_t)target_arg64(arg3, arg4);
|
||||
setsize = arg5;
|
||||
target_mask = arg6;
|
||||
#else
|
||||
id = (id_t)arg3;
|
||||
setsize = arg4;
|
||||
target_mask = arg5;
|
||||
#endif
|
||||
|
||||
ret = copy_from_user_cpuset_mask(&mask, target_mask);
|
||||
if (ret == 0) {
|
||||
ret = get_errno(cpuset_setaffinity(level, which, id, setsize, &mask));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* cpuset_getdomain(2) */
|
||||
/* cpuset_getdomain(cpulevel_t, cpuwhich_t, id_t, size_t, const cpuset_t *);*/
|
||||
static inline abi_long do_freebsd_cpuset_getdomain(cpulevel_t level,
|
||||
cpuwhich_t which, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5,
|
||||
abi_long arg6)
|
||||
{
|
||||
qemu_log("qemu: Unsupported syscall cpuset_getdomain()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* cpuset_setdomain(2) */
|
||||
/* cpuset_setdomain(cpulevel_t, cpuwhich_t, id_t, size_t, const cpuset_t *);*/
|
||||
static inline abi_long do_freebsd_cpuset_setdomain(cpulevel_t level,
|
||||
cpuwhich_t which, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5,
|
||||
abi_long arg6)
|
||||
{
|
||||
qemu_log("qemu: Unsupported syscall cpuset_getdomain()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
|
||||
/* modfnext(2) */
|
||||
static inline abi_long do_freebsd_modfnext(abi_long modid)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall modfnext()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* modfind(2) */
|
||||
static inline abi_long do_freebsd_modfind(abi_ulong target_name)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall modfind()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* kldload(2) */
|
||||
static inline abi_long do_freebsd_kldload(abi_ulong target_name)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall kldload()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* kldunload(2) */
|
||||
static inline abi_long do_freebsd_kldunload(abi_long fileid)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall kldunload()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* kldunloadf(2) */
|
||||
static inline abi_long do_freebsd_kldunloadf(abi_long fileid, abi_long flags)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall kldunloadf()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* kldfind(2) */
|
||||
static inline abi_long do_freebsd_kldfind(abi_ulong target_name)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall kldfind()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* kldnext(2) */
|
||||
static inline abi_long do_freebsd_kldnext(abi_long fileid)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall kldnext()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
|
||||
/* kldstat(2) */
|
||||
static inline abi_long do_freebsd_kldstat(abi_long fileid,
|
||||
abi_ulong target_stat)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall kldstat()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* kldfirstmod(2) */
|
||||
static inline abi_long do_freebsd_kldfirstmod(abi_long fileid)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall kldfirstmod()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* kldsym(2) */
|
||||
static inline abi_long do_freebsd_kldsym(abi_long fileid, abi_long cmd,
|
||||
abi_ulong target_data)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall kldsym()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Resource limits (undocumented except for rctl(8) and rctl.conf(5) )
|
||||
*/
|
||||
/* rctl_get_racct() */
|
||||
static inline abi_long do_freebsd_rctl_get_racct(abi_ulong target_inbufp,
|
||||
abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall rctl_get_racct()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* rctl_get_rules() */
|
||||
static inline abi_long do_freebsd_rctl_get_rules(abi_ulong target_inbufp,
|
||||
abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall rctl_get_rules()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* rctl_add_rule() */
|
||||
static inline abi_long do_freebsd_rctl_add_rule(abi_ulong target_inbufp,
|
||||
abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall rctl_add_rule()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* rctl_remove_rule() */
|
||||
static inline abi_long do_freebsd_rctl_remove_rule(abi_ulong target_inbufp,
|
||||
abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall rctl_remove_rule()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* rctl_get_limits() */
|
||||
static inline abi_long do_freebsd_rctl_get_limits(abi_ulong target_inbufp,
|
||||
abi_ulong inbuflen, abi_ulong target_outbufp, abi_ulong outbuflen)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall rctl_get_limits()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Kernel environment
|
||||
*/
|
||||
|
||||
/* kenv(2) */
|
||||
static inline abi_long do_freebsd_kenv(abi_long what, abi_ulong target_name,
|
||||
abi_ulong target_value, abi_long len)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall kenv()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Mandatory Access Control
|
||||
*/
|
||||
|
||||
/* __mac_get_proc */
|
||||
static inline abi_long do_freebsd___mac_get_proc(abi_ulong target_mac)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall mac_get_proc()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* __mac_set_proc */
|
||||
static inline abi_long do_freebsd___mac_set_proc(abi_ulong target_mac)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall mac_set_proc()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
|
||||
/* __mac_get_fd */
|
||||
static inline abi_long do_freebsd___mac_get_fd(abi_long fd,
|
||||
abi_ulong target_mac)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall mac_get_fd()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* __mac_set_fd */
|
||||
static inline abi_long do_freebsd___mac_set_fd(abi_long fd,
|
||||
abi_ulong target_mac)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall mac_set_fd()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* __mac_get_file */
|
||||
static inline abi_long do_freebsd___mac_get_file(abi_ulong target_path,
|
||||
abi_ulong target_mac)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall mac_get_file()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* __mac_set_file */
|
||||
static inline abi_long do_freebsd___mac_set_file(abi_ulong target_path,
|
||||
abi_ulong target_mac)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall mac_set_file()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* __mac_get_link */
|
||||
static inline abi_long do_freebsd___mac_get_link(abi_ulong target_path,
|
||||
abi_ulong target_mac)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall mac_get_link()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* __mac_set_link */
|
||||
static inline abi_long do_freebsd___mac_set_link(abi_ulong target_path,
|
||||
abi_ulong target_mac)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall mac_set_link()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* mac_syscall */
|
||||
static inline abi_long do_freebsd_mac_syscall(abi_ulong target_policy,
|
||||
abi_long call, abi_ulong target_arg)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall mac_syscall()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* New posix calls
|
||||
*/
|
||||
|
||||
#if TARGET_ABI_BITS == 32
|
||||
static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
|
||||
{
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
return ((uint64_t)word0 << 32) | word1;
|
||||
#else
|
||||
return ((uint64_t)word1 << 32) | word0;
|
||||
#endif
|
||||
}
|
||||
#else /* TARGET_ABI_BITS == 32 */
|
||||
static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
|
||||
{
|
||||
return word0;
|
||||
}
|
||||
#endif /* TARGET_ABI_BITS != 32 */
|
||||
|
||||
/* posix_fallocate(2) */
|
||||
static inline abi_long do_freebsd_posix_fallocate(abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
|
||||
{
|
||||
|
||||
#if TARGET_ABI_BITS == 32
|
||||
return get_errno(posix_fallocate(arg1, target_offset64(arg3, arg4),
|
||||
target_offset64(arg5, arg6)));
|
||||
#else
|
||||
return get_errno(posix_fallocate(arg1, arg2, arg3));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* posix_openpt(2) */
|
||||
static inline abi_long do_freebsd_posix_openpt(abi_long flags)
|
||||
{
|
||||
|
||||
return get_errno(posix_openpt(flags));
|
||||
}
|
||||
|
||||
/* posix_fadvise(2) */
|
||||
static inline abi_long do_freebsd_posix_fadvise(abi_long fd, abi_ulong offset,
|
||||
abi_ulong len, abi_long advise)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall posix_fadvise()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 1300048
|
||||
/* shm_open2(2) */
|
||||
static inline abi_long do_freebsd_shm_open2(abi_ulong pathptr, abi_ulong flags,
|
||||
abi_long mode, abi_ulong shmflags, abi_ulong nameptr)
|
||||
{
|
||||
int ret;
|
||||
void *uname, *upath;
|
||||
|
||||
#ifdef SHM_ANON
|
||||
#define SHM_PATH(p) (p) == SHM_ANON ? (p) : path(p)
|
||||
if (pathptr == (uintptr_t)SHM_ANON) {
|
||||
upath = SHM_ANON;
|
||||
} else
|
||||
#else
|
||||
#define SHM_PATH(p) path(p)
|
||||
#endif
|
||||
{
|
||||
upath = lock_user_string(pathptr);
|
||||
if (upath == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
uname = NULL;
|
||||
if (nameptr != 0) {
|
||||
uname = lock_user_string(nameptr);
|
||||
if (uname == NULL) {
|
||||
unlock_user(upath, pathptr, 0);
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
}
|
||||
ret = get_errno(shm_open2(SHM_PATH(upath),
|
||||
target_to_host_bitmask(flags, fcntl_flags_tbl), mode,
|
||||
target_to_host_bitmask(shmflags, shmflag_flags_tbl), uname));
|
||||
|
||||
#ifdef SHM_ANON
|
||||
if (upath != SHM_ANON)
|
||||
#endif
|
||||
{
|
||||
unlock_user(upath, pathptr, 0);
|
||||
}
|
||||
if (uname != NULL) {
|
||||
unlock_user(uname, nameptr, 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#undef SHM_PATH
|
||||
#endif /* __FreeBSD_version >= 1300048 */
|
||||
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 1300049
|
||||
/* shm_rename(2) */
|
||||
static inline abi_long do_freebsd_shm_rename(abi_ulong fromptr, abi_ulong toptr,
|
||||
abi_ulong flags)
|
||||
{
|
||||
int ret;
|
||||
void *ufrom, *uto;
|
||||
|
||||
ufrom = lock_user_string(fromptr);
|
||||
if (ufrom == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
uto = lock_user_string(toptr);
|
||||
if (uto == NULL) {
|
||||
unlock_user(ufrom, fromptr, 0);
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(shm_rename(ufrom, uto, flags));
|
||||
unlock_user(ufrom, fromptr, 0);
|
||||
unlock_user(uto, toptr, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* __FreeBSD_version >= 1300049 */
|
||||
|
||||
#if defined(HAVE_GETRANDOM)
|
||||
static inline abi_long do_freebsd_getrandom(abi_ulong buf, abi_ulong buflen,
|
||||
abi_ulong flags)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
|
||||
p = lock_user(VERIFY_WRITE, buf, buflen, 0);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(getrandom(p, buflen, flags));
|
||||
unlock_user(p, buf, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ! __OS_MISC_H_ */
|
|
@ -0,0 +1,619 @@
|
|||
/*
|
||||
* FreeBSD process related emulation code
|
||||
*
|
||||
* Copyright (c) 2013-15 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/>.
|
||||
*/
|
||||
|
||||
#define _WANT_FREEBSD11_STAT
|
||||
#define _WANT_FREEBSD11_STATFS
|
||||
#define _WANT_FREEBSD11_DIRENT
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/unistd.h>
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
|
||||
#include <sys/socket.h>
|
||||
struct kinfo_proc;
|
||||
#include <libprocstat.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
|
||||
#include "qemu.h"
|
||||
|
||||
/*
|
||||
* Get the filename for the given file descriptor.
|
||||
* Note that this may return NULL (fail) if no longer cached in the kernel.
|
||||
*/
|
||||
static char *
|
||||
get_filename_from_fd(pid_t pid, int fd, char *filename, size_t len)
|
||||
{
|
||||
char *ret = NULL;
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
|
||||
unsigned int cnt;
|
||||
struct procstat *procstat = NULL;
|
||||
struct kinfo_proc *kp = NULL;
|
||||
struct filestat_list *head = NULL;
|
||||
struct filestat *fst;
|
||||
|
||||
procstat = procstat_open_sysctl();
|
||||
if (procstat == NULL)
|
||||
goto out;
|
||||
|
||||
kp = procstat_getprocs(procstat, KERN_PROC_PID, pid, &cnt);
|
||||
if (kp == NULL)
|
||||
goto out;
|
||||
|
||||
head = procstat_getfiles(procstat, kp, 0);
|
||||
if (head == NULL)
|
||||
goto out;
|
||||
|
||||
STAILQ_FOREACH(fst, head, next) {
|
||||
if (fd == fst->fs_fd) {
|
||||
if (fst->fs_path != NULL) {
|
||||
(void)strlcpy(filename, fst->fs_path, len);
|
||||
ret = filename;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (head != NULL)
|
||||
procstat_freefiles(procstat, head);
|
||||
if (kp != NULL)
|
||||
procstat_freeprocs(procstat, kp);
|
||||
if (procstat != NULL)
|
||||
procstat_close(procstat);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version < 1100000
|
||||
static int
|
||||
is_target_shell_script(int fd, char *interp, size_t size, char **interp_args)
|
||||
{
|
||||
char buf[2], *p, *b;
|
||||
ssize_t n;
|
||||
|
||||
if (fd < 0) {
|
||||
return 0;
|
||||
}
|
||||
(void)lseek(fd, 0L, SEEK_SET);
|
||||
if (read(fd, buf, 2) != 2) {
|
||||
return 0;
|
||||
}
|
||||
if (buf[0] != '#' && buf[1] != '!') {
|
||||
return 0;
|
||||
}
|
||||
if (size == 0) {
|
||||
return 0;
|
||||
}
|
||||
b = interp;
|
||||
/* Remove the trailing whitespace after "#!", if any. */
|
||||
while (size != 0) {
|
||||
n = read(fd, b, 1);
|
||||
if (n < 0 || n == 0) {
|
||||
return 0;
|
||||
}
|
||||
if ((*b != ' ') && (*b != '\t')) {
|
||||
b++;
|
||||
size--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (size != 0) {
|
||||
n = read(fd, b, size);
|
||||
if (n < 0 || n == 0) {
|
||||
return 0;
|
||||
}
|
||||
if ((p = memchr(b, '\n', size)) != NULL) {
|
||||
int hasargs = 0;
|
||||
*p = 0;
|
||||
|
||||
*interp_args = NULL;
|
||||
p = interp;
|
||||
while (*p) {
|
||||
if ((*p == ' ') || (*p == '\t')) {
|
||||
hasargs = 1;
|
||||
*p = 0;
|
||||
} else if (hasargs) {
|
||||
*interp_args = p;
|
||||
break;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
b += n;
|
||||
size -= n;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* execve/fexecve
|
||||
*/
|
||||
abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
|
||||
abi_ulong guest_envp, int do_fexec)
|
||||
{
|
||||
char **argp, **envp, **qargp, **qarg1, **qarg0, **qargend;
|
||||
int argc, envc;
|
||||
abi_ulong gp;
|
||||
abi_ulong addr;
|
||||
char **q;
|
||||
int total_size = 0;
|
||||
void *p;
|
||||
abi_long ret;
|
||||
|
||||
argc = 0;
|
||||
for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
|
||||
if (get_user_ual(addr, gp)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if (!addr) {
|
||||
break;
|
||||
}
|
||||
argc++;
|
||||
}
|
||||
envc = 0;
|
||||
for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
|
||||
if (get_user_ual(addr, gp)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if (!addr) {
|
||||
break;
|
||||
}
|
||||
envc++;
|
||||
}
|
||||
|
||||
qarg0 = argp = g_new0(char *, argc + 9);
|
||||
/* save the first agrument for the emulator */
|
||||
*argp++ = (char *)getprogname();
|
||||
qargp = argp;
|
||||
*argp++ = (char *)getprogname();
|
||||
qarg1 = argp;
|
||||
envp = g_new0(char *, envc + 1);
|
||||
for (gp = guest_argp, q = argp; gp; gp += sizeof(abi_ulong), q++) {
|
||||
if (get_user_ual(addr, gp)) {
|
||||
ret = -TARGET_EFAULT;
|
||||
goto execve_end;
|
||||
}
|
||||
if (!addr) {
|
||||
break;
|
||||
}
|
||||
*q = lock_user_string(addr);
|
||||
if (*q == NULL) {
|
||||
ret = -TARGET_EFAULT;
|
||||
goto execve_end;
|
||||
}
|
||||
total_size += strlen(*q) + 1;
|
||||
}
|
||||
*q++ = NULL;
|
||||
qargend = q;
|
||||
|
||||
for (gp = guest_envp, q = envp; gp; gp += sizeof(abi_ulong), q++) {
|
||||
if (get_user_ual(addr, gp)) {
|
||||
ret = -TARGET_EFAULT;
|
||||
goto execve_end;
|
||||
}
|
||||
if (!addr) {
|
||||
break;
|
||||
}
|
||||
*q = lock_user_string(addr);
|
||||
if (*q == NULL) {
|
||||
ret = -TARGET_EFAULT;
|
||||
goto execve_end;
|
||||
}
|
||||
total_size += strlen(*q) + 1;
|
||||
}
|
||||
*q = NULL;
|
||||
|
||||
/*
|
||||
* This case will not be caught by the host's execve() if its
|
||||
* page size is bigger than the target's.
|
||||
*/
|
||||
if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) {
|
||||
ret = -TARGET_E2BIG;
|
||||
goto execve_end;
|
||||
}
|
||||
|
||||
if (do_fexec) {
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version < 1100000
|
||||
char execpath[PATH_MAX], *scriptargs;
|
||||
#endif /* __FreeBSD_version < 1100000 */
|
||||
|
||||
if (((int)path_or_fd > 0 &&
|
||||
is_target_elf_binary((int)path_or_fd)) == 1) {
|
||||
char execpath[PATH_MAX];
|
||||
|
||||
/*
|
||||
* The executable is an elf binary for the target
|
||||
* arch. execve() it using the emulator if we can
|
||||
* determine the filename path from the fd.
|
||||
*/
|
||||
if (get_filename_from_fd(getpid(), (int)path_or_fd, execpath,
|
||||
sizeof(execpath)) != NULL) {
|
||||
memmove(qarg1 + 2, qarg1, (qargend-qarg1) * sizeof(*qarg1));
|
||||
qarg1[1] = qarg1[0];
|
||||
qarg1[0] = (char *)"-0";
|
||||
qarg1 += 2;
|
||||
qargend += 2;
|
||||
*qarg1 = execpath;
|
||||
#ifndef DONT_INHERIT_INTERP_PREFIX
|
||||
memmove(qarg1 + 2, qarg1, (qargend-qarg1) * sizeof(*qarg1));
|
||||
*qarg1++ = (char *)"-L";
|
||||
*qarg1++ = (char *)interp_prefix;
|
||||
#endif
|
||||
ret = get_errno(execve(qemu_proc_pathname, qargp, envp));
|
||||
} else {
|
||||
/* Getting the filename path failed. */
|
||||
ret = -TARGET_EBADF;
|
||||
goto execve_end;
|
||||
}
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version < 1100000
|
||||
} else if (is_target_shell_script((int)path_or_fd, execpath,
|
||||
sizeof(execpath), &scriptargs) != 0) {
|
||||
char scriptpath[PATH_MAX];
|
||||
|
||||
/* execve() as a target script using emulator. */
|
||||
if (get_filename_from_fd(getpid(), (int)path_or_fd, scriptpath,
|
||||
sizeof(scriptpath)) != NULL) {
|
||||
*qargp = execpath;
|
||||
*qarg1 = scriptpath;
|
||||
#ifndef DONT_INHERIT_INTERP_PREFIX
|
||||
memmove(qargp + 2, qargp, (qargend-qargp) * sizeof(*qargp));
|
||||
qargp[0] = (char *)"-L";
|
||||
qargp[1] = (char *)interp_prefix;
|
||||
qarg1 += 2;
|
||||
qargend += 2;
|
||||
#endif
|
||||
if (scriptargs) {
|
||||
memmove(qarg1 + 1, qarg1, (qargend-qarg1) * sizeof(*qarg1));
|
||||
*qarg1 = scriptargs;
|
||||
}
|
||||
ret = get_errno(execve(qemu_proc_pathname, qarg0, envp));
|
||||
} else {
|
||||
ret = -TARGET_EBADF;
|
||||
goto execve_end;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
ret = get_errno(fexecve((int)path_or_fd, argp, envp));
|
||||
}
|
||||
} else {
|
||||
int fd;
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version < 1100000
|
||||
char execpath[PATH_MAX], *scriptargs;
|
||||
#endif
|
||||
|
||||
p = lock_user_string(path_or_fd);
|
||||
if (p == NULL) {
|
||||
ret = -TARGET_EFAULT;
|
||||
goto execve_end;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the header and see if it a target elf binary. If so
|
||||
* then execute using qemu user mode emulator.
|
||||
*/
|
||||
fd = open(p, O_RDONLY | O_CLOEXEC);
|
||||
if (fd > 0 && is_target_elf_binary(fd) == 1) {
|
||||
close(fd);
|
||||
/* execve() as a target binary using emulator. */
|
||||
memmove(qarg1 + 2, qarg1, (qargend-qarg1) * sizeof(*qarg1));
|
||||
qarg1[1] = qarg1[0];
|
||||
qarg1[0] = (char *)"-0";
|
||||
qarg1 += 2;
|
||||
qargend += 2;
|
||||
*qarg1 = (char *)p;
|
||||
#ifndef DONT_INHERIT_INTERP_PREFIX
|
||||
memmove(qarg1 + 2, qarg1, (qargend-qarg1) * sizeof(*qarg1));
|
||||
*qarg1++ = (char *)"-L";
|
||||
*qarg1++ = (char *)interp_prefix;
|
||||
#endif
|
||||
ret = get_errno(execve(qemu_proc_pathname, qargp, envp));
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version < 1100000
|
||||
} else if (is_target_shell_script(fd, execpath,
|
||||
sizeof(execpath), &scriptargs) != 0) {
|
||||
close(fd);
|
||||
/* execve() as a target script using emulator. */
|
||||
*qargp = execpath;
|
||||
*qarg1 = (char *)p;
|
||||
#ifndef DONT_INHERIT_INTERP_PREFIX
|
||||
memmove(qargp + 2, qargp, (qargend-qargp) * sizeof(*qargp));
|
||||
qargp[0] = (char *)"-L";
|
||||
qargp[1] = (char *)interp_prefix;
|
||||
qarg1 += 2;
|
||||
qargend += 2;
|
||||
#endif
|
||||
if (scriptargs) {
|
||||
memmove(qarg1 + 1, qarg1, (qargend-qarg1) * sizeof(*qarg1));
|
||||
*qarg1 = scriptargs;
|
||||
}
|
||||
ret = get_errno(execve(qemu_proc_pathname, qarg0, envp));
|
||||
#endif
|
||||
} else {
|
||||
close(fd);
|
||||
/* Execve() as a host native binary. */
|
||||
ret = get_errno(execve(p, argp, envp));
|
||||
}
|
||||
unlock_user(p, path_or_fd, 0);
|
||||
}
|
||||
|
||||
execve_end:
|
||||
for (gp = guest_argp, q = argp; *q; gp += sizeof(abi_ulong), q++) {
|
||||
if (get_user_ual(addr, gp) || !addr) {
|
||||
break;
|
||||
}
|
||||
unlock_user(*q, addr, 0);
|
||||
}
|
||||
|
||||
for (gp = guest_envp, q = envp; *q; gp += sizeof(abi_ulong), q++) {
|
||||
if (get_user_ual(addr, gp) || !addr) {
|
||||
break;
|
||||
}
|
||||
unlock_user(*q, addr, 0);
|
||||
}
|
||||
|
||||
g_free(qarg0);
|
||||
g_free(envp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if !defined(__FreeBSD_version)
|
||||
#error __FreeBSD_version not defined!
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 1001510
|
||||
#include <sys/procctl.h>
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 1001510 && defined(PROC_REAP_ACQUIRE)
|
||||
|
||||
static abi_long
|
||||
t2h_procctl_cmd(int target_cmd, int *host_cmd)
|
||||
{
|
||||
|
||||
switch(target_cmd) {
|
||||
case TARGET_PROC_SPROTECT:
|
||||
*host_cmd = PROC_SPROTECT;
|
||||
break;
|
||||
|
||||
case TARGET_PROC_REAP_ACQUIRE:
|
||||
*host_cmd = PROC_REAP_ACQUIRE;
|
||||
break;
|
||||
|
||||
case TARGET_PROC_REAP_RELEASE:
|
||||
*host_cmd = PROC_REAP_RELEASE;
|
||||
break;
|
||||
|
||||
case TARGET_PROC_REAP_STATUS:
|
||||
*host_cmd = PROC_REAP_STATUS;
|
||||
break;
|
||||
|
||||
case TARGET_PROC_REAP_KILL:
|
||||
*host_cmd = PROC_REAP_KILL;
|
||||
break;
|
||||
|
||||
default:
|
||||
return (-TARGET_EINVAL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static abi_long
|
||||
t2h_reaper_kill(abi_ulong target_rk_addr, struct procctl_reaper_kill *host_rk)
|
||||
{
|
||||
struct target_procctl_reaper_kill *target_rk;
|
||||
|
||||
if (!lock_user_struct(VERIFY_READ, target_rk, target_rk_addr, 1))
|
||||
return -TARGET_EFAULT;
|
||||
__get_user(host_rk->rk_sig, &target_rk->rk_sig);
|
||||
__get_user(host_rk->rk_flags, &target_rk->rk_flags);
|
||||
__get_user(host_rk->rk_subtree, &target_rk->rk_subtree);
|
||||
__get_user(host_rk->rk_killed, &target_rk->rk_killed);
|
||||
__get_user(host_rk->rk_fpid, &target_rk->rk_fpid);
|
||||
unlock_user_struct(target_rk, target_rk_addr, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static abi_long
|
||||
h2t_reaper_status(struct procctl_reaper_status *host_rs,
|
||||
abi_ulong target_rs_addr)
|
||||
{
|
||||
struct target_procctl_reaper_status *target_rs;
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_rs, target_rs_addr, 0))
|
||||
return -TARGET_EFAULT;
|
||||
__put_user(host_rs->rs_flags, &target_rs->rs_flags);
|
||||
__put_user(host_rs->rs_children, &target_rs->rs_children);
|
||||
__put_user(host_rs->rs_descendants, &target_rs->rs_descendants);
|
||||
__put_user(host_rs->rs_reaper, &target_rs->rs_reaper);
|
||||
__put_user(host_rs->rs_pid, &target_rs->rs_pid);
|
||||
unlock_user_struct(target_rs, target_rs_addr, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static abi_long
|
||||
h2t_reaper_kill(struct procctl_reaper_kill *host_rk, abi_ulong target_rk_addr)
|
||||
{
|
||||
struct target_procctl_reaper_kill *target_rk;
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_rk, target_rk_addr, 0))
|
||||
return -TARGET_EFAULT;
|
||||
__put_user(host_rk->rk_sig, &target_rk->rk_sig);
|
||||
__put_user(host_rk->rk_flags, &target_rk->rk_flags);
|
||||
__put_user(host_rk->rk_subtree, &target_rk->rk_subtree);
|
||||
__put_user(host_rk->rk_killed, &target_rk->rk_killed);
|
||||
__put_user(host_rk->rk_fpid, &target_rk->rk_fpid);
|
||||
unlock_user_struct(target_rk, target_rk_addr, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static abi_long
|
||||
h2t_procctl_reaper_pidinfo(struct procctl_reaper_pidinfo *host_pi,
|
||||
abi_ulong target_pi_addr)
|
||||
{
|
||||
struct target_procctl_reaper_pidinfo *target_pi;
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_pi, target_pi_addr, 0))
|
||||
return -TARGET_EFAULT;
|
||||
__put_user(host_pi->pi_pid, &target_pi->pi_pid);
|
||||
__put_user(host_pi->pi_subtree, &target_pi->pi_subtree);
|
||||
__put_user(host_pi->pi_flags, &target_pi->pi_flags);
|
||||
unlock_user_struct(target_pi, target_pi_addr, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long
|
||||
do_freebsd_procctl(void *cpu_env, int idtype, abi_ulong arg2, abi_ulong arg3,
|
||||
abi_ulong arg4, abi_ulong arg5, abi_ulong arg6)
|
||||
{
|
||||
abi_long error = 0, target_rp_pids;
|
||||
void *data;
|
||||
int host_cmd, flags;
|
||||
uint32_t u, target_rp_count;
|
||||
union {
|
||||
struct procctl_reaper_status rs;
|
||||
struct procctl_reaper_pids rp;
|
||||
struct procctl_reaper_kill rk;
|
||||
} host;
|
||||
struct target_procctl_reaper_pids *target_rp;
|
||||
id_t id; /* 64-bit */
|
||||
int target_cmd;
|
||||
abi_ulong target_arg;
|
||||
|
||||
#if TARGET_ABI_BITS == 32
|
||||
/* See if we need to align the register pairs. */
|
||||
if (regpairs_aligned(cpu_env)) {
|
||||
id = (id_t)target_arg64(arg3, arg4);
|
||||
target_cmd = (int)arg5;
|
||||
target_arg = arg6;
|
||||
} else {
|
||||
id = (id_t)target_arg64(arg2, arg3);
|
||||
target_cmd = (int)arg4;
|
||||
target_arg = arg5;
|
||||
}
|
||||
#else
|
||||
id = (id_t)arg2;
|
||||
target_cmd = (int)arg3;
|
||||
target_arg = arg4;
|
||||
#endif
|
||||
|
||||
error = t2h_procctl_cmd(target_cmd, &host_cmd);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
switch (host_cmd) {
|
||||
case PROC_SPROTECT:
|
||||
data = &flags;
|
||||
break;
|
||||
|
||||
case PROC_REAP_ACQUIRE:
|
||||
case PROC_REAP_RELEASE:
|
||||
if (target_arg == 0)
|
||||
data = NULL;
|
||||
else
|
||||
error = -TARGET_EINVAL;
|
||||
break;
|
||||
|
||||
case PROC_REAP_STATUS:
|
||||
data = &host.rs;
|
||||
break;
|
||||
|
||||
case PROC_REAP_GETPIDS:
|
||||
if (!lock_user_struct(VERIFY_READ, target_rp, target_arg, 1)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__get_user(target_rp_count, &target_rp->rp_count);
|
||||
__get_user(target_rp_pids, &target_rp->rp_pids);
|
||||
unlock_user_struct(target_rp, target_arg, 0);
|
||||
host.rp.rp_count = target_rp_count;
|
||||
/* XXX we should check target_rc_count to see if it is reasonable. */
|
||||
host.rp.rp_pids = alloca(target_rp_count *
|
||||
sizeof(struct procctl_reaper_pidinfo));
|
||||
if (host.rp.rp_pids == NULL)
|
||||
error = -TARGET_ENOMEM;
|
||||
else
|
||||
data = &host.rp;
|
||||
break;
|
||||
|
||||
case PROC_REAP_KILL:
|
||||
error = t2h_reaper_kill(target_arg, &host.rk);
|
||||
break;
|
||||
}
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = get_errno(procctl(idtype, id, host_cmd, data));
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
switch(host_cmd) {
|
||||
case PROC_SPROTECT:
|
||||
if (put_user_s32(flags, target_arg))
|
||||
return -TARGET_EFAULT;
|
||||
break;
|
||||
|
||||
case PROC_REAP_STATUS:
|
||||
error = h2t_reaper_status(&host.rs, target_arg);
|
||||
break;
|
||||
|
||||
case PROC_REAP_GETPIDS:
|
||||
/* copyout reaper pidinfo */
|
||||
for (u = 0; u < target_rp_count; u++) {
|
||||
error = h2t_procctl_reaper_pidinfo(&host.rp.rp_pids[u],
|
||||
target_rp_pids +
|
||||
(u * sizeof(struct target_procctl_reaper_pidinfo)));
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROC_REAP_KILL:
|
||||
error = h2t_reaper_kill(&host.rk, target_arg);
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
#else /* ! __FreeBSD_version >= 1100000 */
|
||||
|
||||
abi_long
|
||||
do_freebsd_procctl(__unused void *cpu_env, __unused int idtype,
|
||||
__unused abi_ulong arg2, __unused abi_ulong arg3,
|
||||
__unused abi_ulong arg4, __unused abi_ulong arg5,
|
||||
__unused abi_ulong arg6)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall procctl()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
|
||||
#endif /* ! __FreeBSD_version >= 1100000 */
|
|
@ -0,0 +1,554 @@
|
|||
/*
|
||||
* process related system call shims and definitions
|
||||
*
|
||||
* Copyright (c) 2013-14 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 __FREEBSD_PROC_H_
|
||||
#define __FREEBSD_PROC_H_
|
||||
|
||||
#include <sys/param.h>
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 1000000
|
||||
#include <sys/procctl.h>
|
||||
#include <sys/signal.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
|
||||
#include <sys/procdesc.h>
|
||||
#endif
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "target_arch_cpu.h"
|
||||
|
||||
pid_t safe_wait4(pid_t wpid, int *status, int options, struct rusage *rusage);
|
||||
pid_t safe_wait6(idtype_t idtype, id_t id, int *status, int options,
|
||||
struct __wrusage *wrusage, siginfo_t *infop);
|
||||
|
||||
extern int __setugid(int flag);
|
||||
extern int pdwait4(int fd, int *status, int options, struct rusage *rusage);
|
||||
|
||||
/* execve(2) */
|
||||
static inline abi_long do_freebsd_execve(abi_ulong path_or_fd, abi_ulong argp,
|
||||
abi_ulong envp)
|
||||
{
|
||||
|
||||
return freebsd_exec_common(path_or_fd, argp, envp, 0);
|
||||
}
|
||||
|
||||
/* fexecve(2) */
|
||||
static inline abi_long do_freebsd_fexecve(abi_ulong path_or_fd, abi_ulong argp,
|
||||
abi_ulong envp)
|
||||
{
|
||||
|
||||
return freebsd_exec_common(path_or_fd, argp, envp, 1);
|
||||
}
|
||||
|
||||
/* wait4(2) */
|
||||
static inline abi_long do_freebsd_wait4(abi_long arg1, abi_ulong target_status,
|
||||
abi_long arg3, abi_ulong target_rusage)
|
||||
{
|
||||
abi_long ret;
|
||||
int status;
|
||||
struct rusage rusage, *rusage_ptr = NULL;
|
||||
|
||||
if (target_rusage) {
|
||||
rusage_ptr = &rusage;
|
||||
}
|
||||
ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
|
||||
if (target_status != 0) {
|
||||
status = host_to_target_waitstatus(status);
|
||||
if (put_user_s32(status, target_status) != 0) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
}
|
||||
if (target_rusage != 0) {
|
||||
host_to_target_rusage(target_rusage, &rusage);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 1000000
|
||||
/* wait6(2) */
|
||||
static inline abi_long do_freebsd_wait6(void *cpu_env, abi_long idtype,
|
||||
abi_long id1, abi_long id2,
|
||||
abi_ulong target_status, abi_long options, abi_ulong target_wrusage,
|
||||
abi_ulong target_infop, abi_ulong pad1)
|
||||
{
|
||||
abi_long ret;
|
||||
int status;
|
||||
struct __wrusage wrusage, *wrusage_ptr = NULL;
|
||||
siginfo_t info;
|
||||
void *p;
|
||||
|
||||
if (regpairs_aligned(cpu_env) != 0) {
|
||||
/* printf("shifting args\n"); */
|
||||
/* 64-bit id is aligned, so shift all the arguments over by one */
|
||||
id1 = id2;
|
||||
id2 = target_status;
|
||||
target_status = options;
|
||||
options = target_wrusage;
|
||||
target_wrusage = target_infop;
|
||||
target_infop = pad1;
|
||||
}
|
||||
|
||||
if (target_wrusage) {
|
||||
wrusage_ptr = &wrusage;
|
||||
}
|
||||
ret = get_errno(safe_wait6(idtype, target_arg64(id1, id2), &status, options, wrusage_ptr, &info));
|
||||
if (target_status != 0) {
|
||||
status = host_to_target_waitstatus(status);
|
||||
if (put_user_s32(status, target_status) != 0) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
}
|
||||
if (target_wrusage != 0) {
|
||||
host_to_target_wrusage(target_wrusage, &wrusage);
|
||||
}
|
||||
if (target_infop != 0) {
|
||||
p = lock_user(VERIFY_WRITE, target_infop, sizeof(target_siginfo_t), 0);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
host_to_target_siginfo(p, &info);
|
||||
unlock_user(p, target_infop, sizeof(target_siginfo_t));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else /* ! __FreeBSD_version >= 1000000 */
|
||||
|
||||
static inline abi_long do_freebsd_wait6( __unused abi_long idtype,
|
||||
__unused abi_long id, __unused abi_ulong target_status,
|
||||
__unused abi_long options, __unused abi_ulong target_wrusage,
|
||||
__unused abi_ulong target_infop)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall wait6()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
#endif /* __FreeBSD_version >= 1000000 */
|
||||
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
|
||||
/* setloginclass(2) */
|
||||
static inline abi_long do_freebsd_setloginclass(abi_ulong arg1)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
|
||||
p = lock_user_string(arg1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(setloginclass(p));
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* getloginclass(2) */
|
||||
static inline abi_long do_freebsd_getloginclass(abi_ulong arg1, abi_ulong arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
|
||||
p = lock_user_string(arg1);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(getloginclass(p, arg2));
|
||||
unlock_user(p, arg1, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* pdwait4(2) */
|
||||
static inline abi_long do_freebsd_pdwait4(abi_long arg1,
|
||||
abi_ulong target_status, abi_long arg3, abi_ulong target_rusage)
|
||||
{
|
||||
abi_long ret;
|
||||
int status;
|
||||
struct rusage rusage, *rusage_ptr = NULL;
|
||||
|
||||
if (target_rusage) {
|
||||
rusage_ptr = &rusage;
|
||||
}
|
||||
ret = get_errno(pdwait4(arg1, &status, arg3, rusage_ptr));
|
||||
if (target_status != 0) {
|
||||
status = host_to_target_waitstatus(status);
|
||||
if (put_user_s32(status, target_status) != 0) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
}
|
||||
if (target_rusage != 0) {
|
||||
host_to_target_rusage(target_rusage, &rusage);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* pdgetpid(2) */
|
||||
static inline abi_long do_freebsd_pdgetpid(abi_long fd, abi_ulong target_pidp)
|
||||
{
|
||||
abi_long ret;
|
||||
pid_t pid;
|
||||
|
||||
ret = get_errno(pdgetpid(fd, &pid));
|
||||
if (!is_error(ret)) {
|
||||
if (put_user_u32(pid, target_pidp)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* setloginclass(2) */
|
||||
static inline abi_long do_freebsd_setloginclass(abi_ulong arg1)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall setloginclass()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* getloginclass(2) */
|
||||
static inline abi_long do_freebsd_getloginclass(abi_ulong arg1, abi_ulong arg2)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall getloginclass()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* pdwait4(2) */
|
||||
static inline abi_long do_freebsd_pdwait4(abi_long arg1,
|
||||
abi_ulong target_status, abi_long arg3, abi_ulong target_rusage)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall pdwait4()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* pdgetpid(2) */
|
||||
static inline abi_long do_freebsd_pdgetpid(abi_long fd, abi_ulong target_pidp)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall pdgetpid()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
#endif /* ! __FreeBSD_version > 900000 */
|
||||
|
||||
/* undocumented __setugid */
|
||||
static inline abi_long do_freebsd___setugid(abi_long arg1)
|
||||
{
|
||||
|
||||
return get_errno(__setugid(arg1));
|
||||
}
|
||||
|
||||
/* fork(2) */
|
||||
static inline abi_long do_freebsd_fork(void *cpu_env)
|
||||
{
|
||||
abi_long ret;
|
||||
abi_ulong child_flag;
|
||||
|
||||
fork_start();
|
||||
ret = fork();
|
||||
if (ret == 0) {
|
||||
/* child */
|
||||
child_flag = 1;
|
||||
target_cpu_clone_regs(cpu_env, 0);
|
||||
} else {
|
||||
/* parent */
|
||||
child_flag = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The fork system call sets a child flag in the second return
|
||||
* value: 0 for parent process, 1 for child process.
|
||||
*/
|
||||
set_second_rval(cpu_env, child_flag);
|
||||
|
||||
fork_end(child_flag);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* vfork(2) */
|
||||
static inline abi_long do_freebsd_vfork(void *cpu_env)
|
||||
{
|
||||
|
||||
return do_freebsd_fork(cpu_env);
|
||||
}
|
||||
|
||||
/* rfork(2) */
|
||||
static inline abi_long do_freebsd_rfork(void *cpu_env, abi_long flags)
|
||||
{
|
||||
abi_long ret;
|
||||
abi_ulong child_flag;
|
||||
|
||||
/*
|
||||
* XXX We need to handle RFMEM here, as well. Neither are safe to execute
|
||||
* as-is on x86 hosts because they'll split memory but not the stack,
|
||||
* wreaking havoc on host architectures that use the stack to store the
|
||||
* return address as both threads try to pop it off. Rejecting RFSPAWN
|
||||
* entirely for now is ok, the only consumer at the moment is posix_spawn
|
||||
* and it will fall back to classic vfork(2) if we return EINVAL.
|
||||
*/
|
||||
if ((flags & TARGET_RFSPAWN) != 0)
|
||||
return -TARGET_EINVAL;
|
||||
fork_start();
|
||||
ret = rfork(flags);
|
||||
if (ret == 0) {
|
||||
/* child */
|
||||
child_flag = 1;
|
||||
target_cpu_clone_regs(cpu_env, 0);
|
||||
} else {
|
||||
/* parent */
|
||||
child_flag = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The fork system call sets a child flag in the second return
|
||||
* value: 0 for parent process, 1 for child process.
|
||||
*/
|
||||
set_second_rval(cpu_env, child_flag);
|
||||
fork_end(child_flag);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
|
||||
/* pdfork(2) */
|
||||
static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong target_fdp,
|
||||
abi_long flags)
|
||||
{
|
||||
abi_long ret;
|
||||
abi_ulong child_flag;
|
||||
int fd;
|
||||
|
||||
fork_start();
|
||||
ret = pdfork(&fd, flags);
|
||||
if (ret == 0) {
|
||||
/* child */
|
||||
child_flag = 1;
|
||||
target_cpu_clone_regs(cpu_env, 0);
|
||||
} else {
|
||||
/* parent */
|
||||
child_flag = 0;
|
||||
}
|
||||
if (put_user_s32(fd, target_fdp)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
|
||||
/*
|
||||
* The fork system call sets a child flag in the second return
|
||||
* value: 0 for parent process, 1 for child process.
|
||||
*/
|
||||
set_second_rval(cpu_env, child_flag);
|
||||
fork_end(child_flag);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* pdfork(2) */
|
||||
static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong arg1,
|
||||
abi_long arg2)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall pdfork()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
#endif /* __FreeBSD_version > 900000 */
|
||||
|
||||
/* jail(2) */
|
||||
static inline abi_long do_freebsd_jail(abi_ulong arg1)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall jail()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* jail_attach(2) */
|
||||
static inline abi_long do_freebsd_jail_attach(abi_long arg1)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall jail_attach()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* jail_remove(2) */
|
||||
static inline abi_long do_freebsd_jail_remove(abi_long arg1)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall jail_remove()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* jail_get(2) */
|
||||
static inline abi_long do_freebsd_jail_get(abi_ulong arg1, abi_long arg2,
|
||||
abi_long arg3)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall jail_get()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* jail_set(2) */
|
||||
static inline abi_long do_freebsd_jail_set(abi_ulong arg1, abi_long arg2,
|
||||
abi_long arg3)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall jail_set()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* cap_enter(2) */
|
||||
static inline abi_long do_freebsd_cap_enter(void)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall cap_enter()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* cap_new(2) */
|
||||
static inline abi_long do_freebsd_cap_new(abi_long arg1, abi_ulong arg2)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall cap_new()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* cap_getrights(2) */
|
||||
static inline abi_long do_freebsd_cap_getrights(abi_long arg1, abi_ulong arg2)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall cap_getrights()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* cap_getmode(2) */
|
||||
static inline abi_long do_freebsd_cap_getmode(abi_ulong arg1)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall cap_getmode()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* cap_rights_limit(2) */
|
||||
static inline abi_long do_freebsd_cap_rights_limit(int arg1, abi_ulong arg2)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall cap_rights_limit()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* cap_ioctls_limit(2) */
|
||||
static inline abi_long do_freebsd_cap_ioctls_limit(int arg1, abi_ulong arg2,
|
||||
abi_ulong arg3)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall cap_ioctls_limit()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* cap_ioctls_get(2) */
|
||||
static inline abi_long do_freebsd_cap_ioctls_get(int arg1, abi_ulong arg2,
|
||||
abi_ulong arg3)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall cap_ioctls_limit()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* cap_fcntls_limit(2) */
|
||||
static inline abi_long do_freebsd_cap_fcntls_limit(int arg1, abi_ulong arg2)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall cap_fcntls_limit()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* cap_fcntls_get(2) */
|
||||
static inline abi_long do_freebsd_cap_fcntls_get(int arg1, abi_ulong arg2)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall cap_fcntls_get()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* audit(2) */
|
||||
static inline abi_long do_freebsd_audit(abi_ulong arg1, abi_ulong arg2)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall audit()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* auditon(2) */
|
||||
static inline abi_long do_freebsd_auditon(abi_long arg1, abi_ulong arg2,
|
||||
abi_ulong arg3)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall auditon()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* getaudit(2) */
|
||||
static inline abi_long do_freebsd_getaudit(abi_ulong arg1)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall getaudit()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* setaudit(2) */
|
||||
static inline abi_long do_freebsd_setaudit(abi_ulong arg1)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall setaudit()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* getaudit_addr(2) */
|
||||
static inline abi_long do_freebsd_getaudit_addr(abi_ulong arg1,
|
||||
abi_ulong arg2)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall getaudit_addr()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* setaudit_addr(2) */
|
||||
static inline abi_long do_freebsd_setaudit_addr(abi_ulong arg1,
|
||||
abi_ulong arg2)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall setaudit_addr()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* auditctl(2) */
|
||||
static inline abi_long do_freebsd_auditctl(abi_ulong arg1)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall auditctl()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
#endif /* ! __FREEBSD_PROC_H_ */
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* FreeBSD signal system call shims
|
||||
*
|
||||
* 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 __FREEBSD_OS_SIGNAL_H_
|
||||
#define __FREEBSD_OS_SIGNAL_H_
|
||||
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
|
||||
#include <sys/procdesc.h>
|
||||
|
||||
/* pdkill(2) */
|
||||
static inline abi_long do_freebsd_pdkill(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
|
||||
return get_errno(pdkill(arg1, arg2));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline abi_long do_freebsd_pdkill(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall pdkill()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
#endif /* ! __FreeBSD_version > 900000 */
|
||||
|
||||
#endif /* ! __FREEBSD_OS_SIGNAL_H_ */
|
|
@ -0,0 +1,243 @@
|
|||
/*
|
||||
* FreeBSD socket related system call helpers
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "qemu.h"
|
||||
#include "qemu-os.h"
|
||||
|
||||
abi_long t2h_freebsd_cmsg(struct msghdr *msgh,
|
||||
struct target_msghdr *target_msgh)
|
||||
{
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
|
||||
socklen_t msg_controllen;
|
||||
abi_ulong target_cmsg_addr;
|
||||
struct target_cmsghdr *target_cmsg, *target_cmsg_start;
|
||||
socklen_t space = 0;
|
||||
|
||||
msg_controllen = tswap32(target_msgh->msg_controllen);
|
||||
if (msg_controllen < sizeof(struct target_cmsghdr))
|
||||
goto the_end;
|
||||
target_cmsg_addr = tswapal(target_msgh->msg_control);
|
||||
target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
|
||||
target_cmsg_start = target_cmsg;
|
||||
if (!target_cmsg)
|
||||
return -TARGET_EFAULT;
|
||||
|
||||
while (cmsg && target_cmsg) {
|
||||
void *data = CMSG_DATA(cmsg);
|
||||
void *target_data = TARGET_CMSG_DATA(target_cmsg);
|
||||
|
||||
int len = (unsigned char *)(target_cmsg) + tswap32(target_cmsg->cmsg_len) -
|
||||
(unsigned char *)target_data;
|
||||
|
||||
space += CMSG_SPACE(len);
|
||||
if (space > msgh->msg_controllen) {
|
||||
space -= CMSG_SPACE(len);
|
||||
/* This is a QEMU bug, since we allocated the payload
|
||||
* area ourselves (unlike overflow in host-to-target
|
||||
* conversion, which is just the guest giving us a buffer
|
||||
* that's too small). It can't happen for the payload types
|
||||
* we currently support; if it becomes an issue in future
|
||||
* we would need to improve our allocation strategy to
|
||||
* something more intelligent than "twice the size of the
|
||||
* target buffer we're reading from".
|
||||
*/
|
||||
gemu_log("Host cmsg overflow\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
} else {
|
||||
cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
|
||||
}
|
||||
cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
|
||||
cmsg->cmsg_len = CMSG_LEN(len);
|
||||
|
||||
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
|
||||
int *fd = (int *)data;
|
||||
int *target_fd = (int *)target_data;
|
||||
int i, numfds = len / sizeof(int);
|
||||
|
||||
for (i = 0; i < numfds; i++) {
|
||||
__get_user(fd[i], target_fd + i);
|
||||
}
|
||||
} else if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) &&
|
||||
(cmsg->cmsg_type == SCM_TIMESTAMP) &&
|
||||
(len == sizeof(struct target_freebsd_timeval))) {
|
||||
/* copy struct timeval to host */
|
||||
struct timeval *tv = (struct timeval *)data;
|
||||
struct target_freebsd_timeval *target_tv =
|
||||
(struct target_freebsd_timeval *)target_data;
|
||||
__get_user(tv->tv_sec, &target_tv->tv_sec);
|
||||
__get_user(tv->tv_usec, &target_tv->tv_usec);
|
||||
} else {
|
||||
gemu_log("t2h Unsupported ancillary data: %d/%d\n",
|
||||
cmsg->cmsg_level, cmsg->cmsg_type);
|
||||
memcpy(data, target_data, len);
|
||||
}
|
||||
|
||||
cmsg = CMSG_NXTHDR(msgh, cmsg);
|
||||
target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
|
||||
target_cmsg_start);
|
||||
}
|
||||
unlock_user(target_cmsg, target_cmsg_addr, 0);
|
||||
the_end:
|
||||
msgh->msg_controllen = space;
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long h2t_freebsd_cmsg(struct target_msghdr *target_msgh,
|
||||
struct msghdr *msgh)
|
||||
{
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
|
||||
socklen_t msg_controllen;
|
||||
abi_ulong target_cmsg_addr;
|
||||
struct target_cmsghdr *target_cmsg, *target_cmsg_start;
|
||||
socklen_t space = 0;
|
||||
|
||||
msg_controllen = tswap32(target_msgh->msg_controllen);
|
||||
if (msg_controllen < sizeof(struct target_cmsghdr)) {
|
||||
goto the_end;
|
||||
}
|
||||
target_cmsg_addr = tswapal(target_msgh->msg_control);
|
||||
target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
|
||||
target_cmsg_start = target_cmsg;
|
||||
if (!target_cmsg)
|
||||
return -TARGET_EFAULT;
|
||||
|
||||
while (cmsg && target_cmsg) {
|
||||
void *data = CMSG_DATA(cmsg);
|
||||
void *target_data = TARGET_CMSG_DATA(target_cmsg);
|
||||
|
||||
int len = (unsigned char *)(cmsg) + cmsg->cmsg_len -
|
||||
(unsigned char *)data;
|
||||
|
||||
int tgt_len, tgt_space;
|
||||
|
||||
/* We never copy a half-header but may copy half-data;
|
||||
* this is Linux's behaviour in put_cmsg(). Note that
|
||||
* truncation here is a guest problem (which we report
|
||||
* to the guest via the CTRUNC bit), unlike truncation
|
||||
* in target_to_host_cmsg, which is a QEMU bug.
|
||||
*/
|
||||
if (msg_controllen < sizeof(struct target_cmsghdr)) {
|
||||
target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
|
||||
break;
|
||||
}
|
||||
|
||||
if (cmsg->cmsg_level == SOL_SOCKET) {
|
||||
target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
|
||||
} else {
|
||||
target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
|
||||
}
|
||||
target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
|
||||
|
||||
/* Payload types which need a different size of payload on
|
||||
* the target must adjust tgt_len here.
|
||||
*/
|
||||
tgt_len = len;
|
||||
switch (cmsg->cmsg_level) {
|
||||
case SOL_SOCKET:
|
||||
switch (cmsg->cmsg_type) {
|
||||
case SCM_TIMESTAMP:
|
||||
tgt_len = sizeof(struct target_freebsd_timeval);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (msg_controllen < TARGET_CMSG_LEN(tgt_len)) {
|
||||
target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
|
||||
tgt_len = msg_controllen - sizeof(struct target_cmsghdr);
|
||||
}
|
||||
|
||||
/* We must now copy-and-convert len bytes of payload
|
||||
* into tgt_len bytes of destination space. Bear in mind
|
||||
* that in both source and destination we may be dealing
|
||||
* with a truncated value!
|
||||
*/
|
||||
switch (cmsg->cmsg_level) {
|
||||
case SOL_SOCKET:
|
||||
switch (cmsg->cmsg_type) {
|
||||
case SCM_RIGHTS:
|
||||
{
|
||||
int *fd = (int *)data;
|
||||
int *target_fd = (int *)target_data;
|
||||
int i, numfds = tgt_len / sizeof(int);
|
||||
|
||||
for (i = 0; i < numfds; i++) {
|
||||
__put_user(fd[i], target_fd + i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SO_TIMESTAMP:
|
||||
{
|
||||
struct timeval *tv = (struct timeval *)data;
|
||||
struct target_freebsd_timeval *target_tv =
|
||||
(struct target_freebsd_timeval *)target_data;
|
||||
|
||||
if (len != sizeof(struct timeval) ||
|
||||
tgt_len != sizeof(struct target_freebsd_timeval)) {
|
||||
goto unimplemented;
|
||||
}
|
||||
|
||||
/* copy struct timeval to target */
|
||||
__put_user(tv->tv_sec, &target_tv->tv_sec);
|
||||
__put_user(tv->tv_usec, &target_tv->tv_usec);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
goto unimplemented;
|
||||
}
|
||||
break; // switch (cmsg->cmsg_type)
|
||||
default:
|
||||
unimplemented:
|
||||
gemu_log("h2t Unsupported ancillary data: %d/%d\n",
|
||||
cmsg->cmsg_level, cmsg->cmsg_type);
|
||||
memcpy(target_data, data, MIN(len, tgt_len));
|
||||
if (tgt_len > len) {
|
||||
memset(target_data + len, 0, tgt_len - len);
|
||||
}
|
||||
}
|
||||
|
||||
target_cmsg->cmsg_len = tswap32(TARGET_CMSG_LEN(tgt_len));
|
||||
tgt_space = TARGET_CMSG_SPACE(tgt_len);
|
||||
if (msg_controllen < tgt_space) {
|
||||
tgt_space = msg_controllen;
|
||||
}
|
||||
msg_controllen -= tgt_space;
|
||||
space += tgt_space;
|
||||
cmsg = CMSG_NXTHDR(msgh, cmsg);
|
||||
target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
|
||||
target_cmsg_start);
|
||||
}
|
||||
unlock_user(target_cmsg, target_cmsg_addr, space);
|
||||
the_end:
|
||||
target_msgh->msg_controllen = tswap32(space);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,833 @@
|
|||
/*
|
||||
* FreeBSD socket related system call shims
|
||||
*
|
||||
* Copyright (c) 2013-14 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 __FREEBSD_SOCKET_H_
|
||||
#define __FREEBSD_SOCKET_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "qemu-os.h"
|
||||
|
||||
ssize_t safe_recvmsg(int s, struct msghdr *msg, int flags);
|
||||
ssize_t safe_sendmsg(int s, const struct msghdr *msg, int flags);
|
||||
|
||||
/* do_sendrecvmsg_locked() Must return target values and target errnos. */
|
||||
static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
|
||||
int flags, int send)
|
||||
{
|
||||
abi_long ret, len;
|
||||
struct msghdr msg;
|
||||
abi_ulong count;
|
||||
struct iovec *vec;
|
||||
abi_ulong target_vec;
|
||||
|
||||
if (msgp->msg_name) {
|
||||
msg.msg_namelen = tswap32(msgp->msg_namelen);
|
||||
msg.msg_name = alloca(msg.msg_namelen+1);
|
||||
ret = target_to_host_sockaddr(msg.msg_name,
|
||||
tswapal(msgp->msg_name),
|
||||
msg.msg_namelen);
|
||||
if (ret == -TARGET_EFAULT) {
|
||||
/* For connected sockets msg_name and msg_namelen must
|
||||
* be ignored, so returning EFAULT immediately is wrong.
|
||||
* Instead, pass a bad msg_name to the host kernel, and
|
||||
* let it decide whether to return EFAULT or not.
|
||||
*/
|
||||
msg.msg_name = (void *)-1;
|
||||
} else if (ret) {
|
||||
goto out2;
|
||||
}
|
||||
} else {
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
}
|
||||
msg.msg_controllen = 2 * tswap32(msgp->msg_controllen);
|
||||
msg.msg_control = alloca(msg.msg_controllen);
|
||||
memset(msg.msg_control, 0, msg.msg_controllen);
|
||||
|
||||
msg.msg_flags = tswap32(msgp->msg_flags);
|
||||
|
||||
count = tswap32(msgp->msg_iovlen);
|
||||
target_vec = tswapal(msgp->msg_iov);
|
||||
|
||||
if (count > IOV_MAX) {
|
||||
/* sendrcvmsg returns a different errno for this condition than
|
||||
* readv/writev, so we must catch it here before lock_iovec() does.
|
||||
*/
|
||||
ret = -TARGET_EMSGSIZE;
|
||||
goto out2;
|
||||
}
|
||||
|
||||
vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
|
||||
target_vec, count, send);
|
||||
if (vec == NULL) {
|
||||
ret = -host_to_target_errno(errno);
|
||||
goto out2;
|
||||
}
|
||||
msg.msg_iovlen = count;
|
||||
msg.msg_iov = vec;
|
||||
|
||||
if (send) {
|
||||
ret = t2h_freebsd_cmsg(&msg, msgp);
|
||||
if (ret == 0) {
|
||||
ret = get_errno(safe_sendmsg(fd, &msg, flags));
|
||||
}
|
||||
} else {
|
||||
ret = get_errno(safe_recvmsg(fd, &msg, flags));
|
||||
if (!is_error(ret)) {
|
||||
len = ret;
|
||||
ret = h2t_freebsd_cmsg(msgp, &msg);
|
||||
if (!is_error(ret)) {
|
||||
msgp->msg_namelen = tswap32(msg.msg_namelen);
|
||||
msgp->msg_flags = tswap32(msg.msg_flags);
|
||||
if (msg.msg_name != NULL && msg.msg_name != (void *)-1) {
|
||||
ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
|
||||
msg.msg_name, msg.msg_namelen);
|
||||
if (ret) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
unlock_iovec(vec, target_vec, count, !send);
|
||||
out2:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
|
||||
int flags, int send)
|
||||
{
|
||||
abi_long ret;
|
||||
struct target_msghdr *msgp;
|
||||
|
||||
if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
|
||||
msgp,
|
||||
target_msg,
|
||||
send ? 1 : 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
|
||||
unlock_user_struct(msgp, target_msg, send ? 0 : 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* setsockopt(2) */
|
||||
static inline abi_long do_bsd_setsockopt(int sockfd, int level, int optname,
|
||||
abi_ulong optval_addr, socklen_t optlen)
|
||||
{
|
||||
abi_long ret;
|
||||
int val;
|
||||
struct ip_mreqn *ip_mreq;
|
||||
void *p;
|
||||
|
||||
switch (level) {
|
||||
case IPPROTO_TCP:
|
||||
/* TCP options all take an 'int' value. */
|
||||
if (optlen < sizeof(uint32_t)) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
if (get_user_u32(val, optval_addr)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
|
||||
break;
|
||||
|
||||
case IPPROTO_IP:
|
||||
switch (optname) {
|
||||
case IP_OPTIONS:
|
||||
p = lock_user(VERIFY_READ, optval_addr, optlen, 0);
|
||||
if (p == NULL)
|
||||
return -TARGET_EFAULT;
|
||||
ret = get_errno(setsockopt(sockfd, level, optname, p, optlen));
|
||||
unlock_user(p, optval_addr, 0);
|
||||
break;
|
||||
case IP_HDRINCL:/* int; header is included with data */
|
||||
case IP_TOS: /* int; IP type of service and preced. */
|
||||
case IP_TTL: /* int; IP time to live */
|
||||
case IP_RECVOPTS: /* bool; receive all IP opts w/dgram */
|
||||
case IP_RECVRETOPTS: /* bool; receive IP opts for response */
|
||||
case IP_RECVDSTADDR: /* bool; receive IP dst addr w/dgram */
|
||||
case IP_MULTICAST_IF:/* u_char; set/get IP multicast i/f */
|
||||
case IP_MULTICAST_TTL:/* u_char; set/get IP multicast ttl */
|
||||
case IP_MULTICAST_LOOP:/*u_char;set/get IP multicast loopback */
|
||||
case IP_PORTRANGE: /* int; range to choose for unspec port */
|
||||
case IP_RECVIF: /* bool; receive reception if w/dgram */
|
||||
case IP_IPSEC_POLICY: /* int; set/get security policy */
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version <= 1100000
|
||||
case IP_FAITH: /* bool; accept FAITH'ed connections */
|
||||
#endif
|
||||
case IP_RECVTTL: /* bool; receive reception TTL w/dgram */
|
||||
val = 0;
|
||||
if (optlen >= sizeof(uint32_t)) {
|
||||
if (get_user_u32(val, optval_addr)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
} else if (optlen >= 1) {
|
||||
if (get_user_u8(val, optval_addr)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
}
|
||||
ret = get_errno(setsockopt(sockfd, level, optname, &val,
|
||||
sizeof(val)));
|
||||
break;
|
||||
|
||||
case IP_ADD_MEMBERSHIP: /*ip_mreq; add an IP group membership */
|
||||
case IP_DROP_MEMBERSHIP:/*ip_mreq; drop an IP group membership*/
|
||||
if (optlen < sizeof(struct target_ip_mreq) ||
|
||||
optlen > sizeof(struct target_ip_mreqn)) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
ip_mreq = (struct ip_mreqn *) alloca(optlen);
|
||||
target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
|
||||
ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq,
|
||||
optlen));
|
||||
break;
|
||||
|
||||
default:
|
||||
goto unimplemented;
|
||||
}
|
||||
break;
|
||||
|
||||
case IPPROTO_IPV6:
|
||||
switch (optname) {
|
||||
case IPV6_UNICAST_HOPS: /* int; IP6 hops */
|
||||
case IPV6_MULTICAST_IF: /* u_int; set/get IP6 multicast i/f */
|
||||
case IPV6_MULTICAST_HOPS: /* int; set/get IP6 multicast hops */
|
||||
case IPV6_MULTICAST_LOOP: /* u_int; set/get IP6 multicast loopback */
|
||||
case IPV6_PORTRANGE: /* int; range to choose for unspec port */
|
||||
case IPV6_CHECKSUM: /* int; checksum offset for raw socket */
|
||||
case IPV6_V6ONLY: /* bool; make AF_INET6 sockets v6 only */
|
||||
case IPV6_RECVPKTINFO: /* bool; recv if, dst addr */
|
||||
case IPV6_RECVHOPLIMIT: /* bool; recv hop limit */
|
||||
case IPV6_RECVRTHDR: /* bool; recv routing header */
|
||||
case IPV6_RECVHOPOPTS: /* bool; recv hop-by-hop option */
|
||||
case IPV6_RECVDSTOPTS: /* bool; recv dst option after rthdr */
|
||||
case IPV6_USE_MIN_MTU: /* bool; send packets at the minimum MTU */
|
||||
case IPV6_RECVPATHMTU: /* bool; notify an according MTU */
|
||||
case IPV6_HOPLIMIT: /* int; send hop limit */
|
||||
case IPV6_RECVTCLASS: /* bool; recv traffic class values */
|
||||
case IPV6_AUTOFLOWLABEL: /* bool; attach flowlabel automagically */
|
||||
case IPV6_TCLASS: /* int; send traffic class value */
|
||||
case IPV6_DONTFRAG: /* bool; disable IPv6 fragmentation */
|
||||
case IPV6_PREFER_TEMPADDR: /* int; prefer temporary addresses */
|
||||
case IPV6_BINDANY: /* bool: allow bind to any address */
|
||||
#ifdef IPV6_BINDMULTI
|
||||
case IPV6_BINDMULTI: /* bool; allow multibind to same addr/port*/
|
||||
#endif /* IPV6_BINDMULTI */
|
||||
#ifdef IPV6_RSS_LISTEN_BUCKET
|
||||
case IPV6_RSS_LISTEN_BUCKET: /* int; set RSS listen bucket */
|
||||
#endif /* IPV6_RSS_LISTEN_BUCKET */
|
||||
#ifdef IPV6_FLOWID
|
||||
case IPV6_FLOWID: /* int; flowid of given socket */
|
||||
#endif /* IPV6_FLOWID */
|
||||
#ifdef IPV6_FLOWTYPE
|
||||
case IPV6_FLOWTYPE: /* int; flowtype of given socket */
|
||||
#endif /* IPV6_FLOWTYPE */
|
||||
#ifdef IPV6_RSSBUCKETID
|
||||
case IPV6_RSSBUCKETID: /* int; RSS bucket ID of given socket */
|
||||
#endif /* IPV6_RSSBUCKETID */
|
||||
val = 0;
|
||||
if (optlen >= sizeof(uint32_t)) {
|
||||
if (get_user_u32(val, optval_addr)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
} else if (optlen >= 1) {
|
||||
if (get_user_u8(val, optval_addr)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
}
|
||||
ret = get_errno(setsockopt(sockfd, level, optname, &val,
|
||||
sizeof(val)));
|
||||
break;
|
||||
|
||||
case IPV6_JOIN_GROUP: /* ipv6_mreq; join a group membership */
|
||||
case IPV6_LEAVE_GROUP: /* ipv6_mreq; leave a group membership */
|
||||
case ICMP6_FILTER: /* icmp6_filter; icmp6 filter */
|
||||
case IPV6_IPSEC_POLICY: /* struct; get/set security policy */
|
||||
case IPV6_FW_ADD: /* add a firewall rule to chain */
|
||||
case IPV6_FW_DEL: /* delete a firewall rule from chain */
|
||||
case IPV6_FW_FLUSH: /* flush firewall rule chain */
|
||||
case IPV6_FW_ZERO: /* clear single/all firewall counter(s) */
|
||||
case IPV6_FW_GET: /* get entire firewall rule chain */
|
||||
case IPV6_RTHDRDSTOPTS: /* ip6_dest; send dst option before rthdr */
|
||||
case IPV6_PATHMTU: /* mtuinfo; get the current path MTU */
|
||||
case IPV6_PKTINFO: /* in6_pktinfo; send if, src addr */
|
||||
case IPV6_NEXTHOP: /* sockaddr; next hop addr */
|
||||
case IPV6_HOPOPTS: /* ip6_hbh; send hop-by-hop option */
|
||||
case IPV6_DSTOPTS: /* ip6_dest; send dst option befor rthdr */
|
||||
case IPV6_RTHDR: /* ip6_rthdr; send routing header */
|
||||
case IPV6_MSFILTER: /* struct __msfilterreq; */
|
||||
default:
|
||||
goto unimplemented;
|
||||
}
|
||||
break;
|
||||
|
||||
case TARGET_SOL_SOCKET:
|
||||
switch (optname) {
|
||||
/* Options with 'int' argument. */
|
||||
case TARGET_SO_DEBUG:
|
||||
optname = SO_DEBUG;
|
||||
break;
|
||||
|
||||
case TARGET_SO_REUSEADDR:
|
||||
optname = SO_REUSEADDR;
|
||||
break;
|
||||
|
||||
case TARGET_SO_REUSEPORT:
|
||||
optname = SO_REUSEADDR;
|
||||
break;
|
||||
|
||||
case TARGET_SO_KEEPALIVE:
|
||||
optname = SO_KEEPALIVE;
|
||||
break;
|
||||
|
||||
case TARGET_SO_DONTROUTE:
|
||||
optname = SO_DONTROUTE;
|
||||
break;
|
||||
|
||||
case TARGET_SO_LINGER:
|
||||
optname = SO_LINGER;
|
||||
break;
|
||||
|
||||
case TARGET_SO_BROADCAST:
|
||||
optname = SO_BROADCAST;
|
||||
break;
|
||||
|
||||
case TARGET_SO_OOBINLINE:
|
||||
optname = SO_OOBINLINE;
|
||||
break;
|
||||
|
||||
case TARGET_SO_SNDBUF:
|
||||
optname = SO_SNDBUF;
|
||||
break;
|
||||
|
||||
case TARGET_SO_RCVBUF:
|
||||
optname = SO_RCVBUF;
|
||||
break;
|
||||
|
||||
case TARGET_SO_SNDLOWAT:
|
||||
optname = SO_RCVLOWAT;
|
||||
break;
|
||||
|
||||
case TARGET_SO_RCVLOWAT:
|
||||
optname = SO_RCVLOWAT;
|
||||
break;
|
||||
|
||||
case TARGET_SO_SNDTIMEO:
|
||||
optname = SO_SNDTIMEO;
|
||||
break;
|
||||
|
||||
case TARGET_SO_RCVTIMEO:
|
||||
optname = SO_RCVTIMEO;
|
||||
break;
|
||||
|
||||
case TARGET_SO_ACCEPTFILTER:
|
||||
goto unimplemented;
|
||||
|
||||
case TARGET_SO_NOSIGPIPE:
|
||||
optname = SO_NOSIGPIPE;
|
||||
break;
|
||||
|
||||
case TARGET_SO_TIMESTAMP:
|
||||
optname = SO_TIMESTAMP;
|
||||
break;
|
||||
|
||||
case TARGET_SO_BINTIME:
|
||||
optname = SO_BINTIME;
|
||||
break;
|
||||
|
||||
case TARGET_SO_ERROR:
|
||||
optname = SO_ERROR;
|
||||
break;
|
||||
|
||||
case TARGET_SO_SETFIB:
|
||||
optname = SO_ERROR;
|
||||
break;
|
||||
|
||||
#ifdef SO_USER_COOKIE
|
||||
case TARGET_SO_USER_COOKIE:
|
||||
optname = SO_USER_COOKIE;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
goto unimplemented;
|
||||
}
|
||||
if (optlen < sizeof(uint32_t)) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
if (get_user_u32(val, optval_addr)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val,
|
||||
sizeof(val)));
|
||||
break;
|
||||
default:
|
||||
unimplemented:
|
||||
gemu_log("Unsupported setsockopt level=%d optname=%d\n",
|
||||
level, optname);
|
||||
ret = -TARGET_ENOPROTOOPT;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* getsockopt(2) */
|
||||
static inline abi_long do_bsd_getsockopt(int sockfd, int level, int optname,
|
||||
abi_ulong optval_addr, abi_ulong optlen)
|
||||
{
|
||||
abi_long ret;
|
||||
int len, val;
|
||||
socklen_t lv;
|
||||
void *p;
|
||||
|
||||
switch (level) {
|
||||
case TARGET_SOL_SOCKET:
|
||||
level = SOL_SOCKET;
|
||||
switch (optname) {
|
||||
|
||||
/* These don't just return a single integer */
|
||||
case TARGET_SO_LINGER:
|
||||
case TARGET_SO_RCVTIMEO:
|
||||
case TARGET_SO_SNDTIMEO:
|
||||
case TARGET_SO_ACCEPTFILTER:
|
||||
goto unimplemented;
|
||||
|
||||
/* Options with 'int' argument. */
|
||||
case TARGET_SO_DEBUG:
|
||||
optname = SO_DEBUG;
|
||||
goto int_case;
|
||||
|
||||
case TARGET_SO_REUSEADDR:
|
||||
optname = SO_REUSEADDR;
|
||||
goto int_case;
|
||||
|
||||
case TARGET_SO_REUSEPORT:
|
||||
optname = SO_REUSEPORT;
|
||||
goto int_case;
|
||||
|
||||
case TARGET_SO_TYPE:
|
||||
optname = SO_TYPE;
|
||||
goto int_case;
|
||||
|
||||
case TARGET_SO_ERROR:
|
||||
optname = SO_ERROR;
|
||||
goto int_case;
|
||||
|
||||
case TARGET_SO_DONTROUTE:
|
||||
optname = SO_DONTROUTE;
|
||||
goto int_case;
|
||||
|
||||
case TARGET_SO_BROADCAST:
|
||||
optname = SO_BROADCAST;
|
||||
goto int_case;
|
||||
|
||||
case TARGET_SO_SNDBUF:
|
||||
optname = SO_SNDBUF;
|
||||
goto int_case;
|
||||
|
||||
case TARGET_SO_RCVBUF:
|
||||
optname = SO_RCVBUF;
|
||||
goto int_case;
|
||||
|
||||
case TARGET_SO_KEEPALIVE:
|
||||
optname = SO_KEEPALIVE;
|
||||
goto int_case;
|
||||
|
||||
case TARGET_SO_OOBINLINE:
|
||||
optname = SO_OOBINLINE;
|
||||
goto int_case;
|
||||
|
||||
case TARGET_SO_TIMESTAMP:
|
||||
optname = SO_TIMESTAMP;
|
||||
goto int_case;
|
||||
|
||||
case TARGET_SO_RCVLOWAT:
|
||||
optname = SO_RCVLOWAT;
|
||||
goto int_case;
|
||||
|
||||
case TARGET_SO_LISTENINCQLEN:
|
||||
optname = SO_LISTENINCQLEN;
|
||||
goto int_case;
|
||||
|
||||
default:
|
||||
int_case:
|
||||
if (get_user_u32(len, optlen)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if (len < 0) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
lv = sizeof(lv);
|
||||
ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
if (len > lv) {
|
||||
len = lv;
|
||||
}
|
||||
if (len == 4) {
|
||||
if (put_user_u32(val, optval_addr)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
} else {
|
||||
if (put_user_u8(val, optval_addr)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
}
|
||||
if (put_user_u32(len, optlen)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case IPPROTO_TCP:
|
||||
/* TCP options all take an 'int' value. */
|
||||
goto int_case;
|
||||
|
||||
case IPPROTO_IP:
|
||||
switch (optname) {
|
||||
case IP_OPTIONS:
|
||||
if (get_user_u32(len, optlen))
|
||||
return -TARGET_EFAULT;
|
||||
lv = (socklen_t)len;
|
||||
p = lock_user(VERIFY_WRITE, optval_addr, len, 0);
|
||||
if (p == NULL)
|
||||
return -TARGET_EFAULT;
|
||||
ret = get_errno(getsockopt(sockfd, level, optname, p, &lv));
|
||||
unlock_user(p, optval_addr, len);
|
||||
if (put_user_u32(lv, optlen))
|
||||
return -TARGET_EFAULT;
|
||||
break;
|
||||
case IP_HDRINCL:
|
||||
case IP_TOS:
|
||||
case IP_TTL:
|
||||
case IP_RECVOPTS:
|
||||
case IP_RECVRETOPTS:
|
||||
case IP_RECVDSTADDR:
|
||||
|
||||
case IP_RETOPTS:
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version > 900000 && defined(IP_RECVTOS)
|
||||
case IP_RECVTOS:
|
||||
#endif
|
||||
case IP_MULTICAST_TTL:
|
||||
case IP_MULTICAST_LOOP:
|
||||
case IP_PORTRANGE:
|
||||
case IP_IPSEC_POLICY:
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version <= 1100000
|
||||
case IP_FAITH:
|
||||
#endif
|
||||
case IP_ONESBCAST:
|
||||
case IP_BINDANY:
|
||||
if (get_user_u32(len, optlen)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if (len < 0) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
lv = sizeof(lv);
|
||||
ret = get_errno(getsockopt(sockfd, level, optname,
|
||||
&val, &lv));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
if (len < sizeof(int) && len > 0 && val >= 0 &&
|
||||
val < 255) {
|
||||
len = 1;
|
||||
if (put_user_u32(len, optlen) ||
|
||||
put_user_u8(val, optval_addr)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
} else {
|
||||
if (len > sizeof(int)) {
|
||||
len = sizeof(int);
|
||||
}
|
||||
if (put_user_u32(len, optlen) ||
|
||||
put_user_u32(val, optval_addr)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
goto unimplemented;
|
||||
}
|
||||
break;
|
||||
|
||||
case IPPROTO_IPV6:
|
||||
switch (optname) {
|
||||
case IPV6_UNICAST_HOPS: /* int; IP6 hops */
|
||||
case IPV6_MULTICAST_IF: /* u_int; set/get IP6 multicast i/f */
|
||||
case IPV6_MULTICAST_HOPS: /* int; set/get IP6 multicast hops */
|
||||
case IPV6_MULTICAST_LOOP: /* u_int; set/get IP6 multicast loopback */
|
||||
case IPV6_PORTRANGE: /* int; range to choose for unspec port */
|
||||
case IPV6_CHECKSUM: /* int; checksum offset for raw socket */
|
||||
case IPV6_V6ONLY: /* bool; make AF_INET6 sockets v6 only */
|
||||
case IPV6_RECVPKTINFO: /* bool; recv if, dst addr */
|
||||
case IPV6_RECVHOPLIMIT: /* bool; recv hop limit */
|
||||
case IPV6_RECVRTHDR: /* bool; recv routing header */
|
||||
case IPV6_RECVHOPOPTS: /* bool; recv hop-by-hop option */
|
||||
case IPV6_RECVDSTOPTS: /* bool; recv dst option after rthdr */
|
||||
case IPV6_USE_MIN_MTU: /* bool; send packets at the minimum MTU */
|
||||
case IPV6_RECVPATHMTU: /* bool; notify an according MTU */
|
||||
case IPV6_HOPLIMIT: /* int; send hop limit */
|
||||
case IPV6_RECVTCLASS: /* bool; recv traffic class values */
|
||||
case IPV6_AUTOFLOWLABEL: /* bool; attach flowlabel automagically */
|
||||
case IPV6_TCLASS: /* int; send traffic class value */
|
||||
case IPV6_DONTFRAG: /* bool; disable IPv6 fragmentation */
|
||||
case IPV6_PREFER_TEMPADDR: /* int; prefer temporary addresses */
|
||||
case IPV6_BINDANY: /* bool: allow bind to any address */
|
||||
#ifdef IPV6_BINDMULTI
|
||||
case IPV6_BINDMULTI: /* bool; allow multibind to same addr/port*/
|
||||
#endif /* IPV6_BINDMULTI */
|
||||
#ifdef IPV6_RSS_LISTEN_BUCKET
|
||||
case IPV6_RSS_LISTEN_BUCKET: /* int; set RSS listen bucket */
|
||||
#endif /* IPV6_RSS_LISTEN_BUCKET */
|
||||
#ifdef IPV6_FLOWID
|
||||
case IPV6_FLOWID: /* int; flowid of given socket */
|
||||
#endif /* IPV6_FLOWID */
|
||||
#ifdef IPV6_FLOWTYPE
|
||||
case IPV6_FLOWTYPE: /* int; flowtype of given socket */
|
||||
#endif /* IPV6_FLOWTYPE */
|
||||
#ifdef IPV6_RSSBUCKETID
|
||||
case IPV6_RSSBUCKETID: /* int; RSS bucket ID of given socket */
|
||||
#endif /* IPV6_RSSBUCKETID */
|
||||
if (get_user_u32(len, optlen)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if (len < 0) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
lv = sizeof(lv);
|
||||
ret = get_errno(getsockopt(sockfd, level, optname,
|
||||
&val, &lv));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
if (len < sizeof(int) && len > 0 && val >= 0 &&
|
||||
val < 255) {
|
||||
len = 1;
|
||||
if (put_user_u32(len, optlen) ||
|
||||
put_user_u8(val, optval_addr)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
} else {
|
||||
if (len > sizeof(int)) {
|
||||
len = sizeof(int);
|
||||
}
|
||||
if (put_user_u32(len, optlen) ||
|
||||
put_user_u32(val, optval_addr)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case IPV6_JOIN_GROUP: /* ipv6_mreq; join a group membership */
|
||||
case IPV6_LEAVE_GROUP: /* ipv6_mreq; leave a group membership */
|
||||
case ICMP6_FILTER: /* icmp6_filter; icmp6 filter */
|
||||
case IPV6_IPSEC_POLICY: /* struct; get/set security policy */
|
||||
case IPV6_FW_ADD: /* add a firewall rule to chain */
|
||||
case IPV6_FW_DEL: /* delete a firewall rule from chain */
|
||||
case IPV6_FW_FLUSH: /* flush firewall rule chain */
|
||||
case IPV6_FW_ZERO: /* clear single/all firewall counter(s) */
|
||||
case IPV6_FW_GET: /* get entire firewall rule chain */
|
||||
case IPV6_RTHDRDSTOPTS: /* ip6_dest; send dst option before rthdr */
|
||||
case IPV6_PATHMTU: /* mtuinfo; get the current path MTU */
|
||||
case IPV6_PKTINFO: /* in6_pktinfo; send if, src addr */
|
||||
case IPV6_NEXTHOP: /* sockaddr; next hop addr */
|
||||
case IPV6_HOPOPTS: /* ip6_hbh; send hop-by-hop option */
|
||||
case IPV6_DSTOPTS: /* ip6_dest; send dst option befor rthdr */
|
||||
case IPV6_RTHDR: /* ip6_rthdr; send routing header */
|
||||
case IPV6_MSFILTER: /* struct __msfilterreq; */
|
||||
default:
|
||||
goto unimplemented;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
unimplemented:
|
||||
gemu_log("getsockopt level=%d optname=%d not yet supported\n",
|
||||
level, optname);
|
||||
ret = -TARGET_EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* setfib(2) */
|
||||
static inline abi_long do_freebsd_setfib(abi_long fib)
|
||||
{
|
||||
|
||||
return get_errno(setfib(fib));
|
||||
}
|
||||
|
||||
/* sctp_peeloff(2) */
|
||||
static inline abi_long do_freebsd_sctp_peeloff(abi_long s, abi_ulong id)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall sctp_peeloff()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* sctp_generic_sendmsg(2) */
|
||||
static inline abi_long do_freebsd_sctp_generic_sendmsg(abi_long s,
|
||||
abi_ulong target_msg, abi_long msglen, abi_ulong target_to,
|
||||
abi_ulong len, abi_ulong target_sinfo, abi_long flags)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall sctp_generic_sendmsg()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* sctp_generic_recvmsg(2) */
|
||||
static inline abi_long do_freebsd_sctp_generic_recvmsg(abi_long s,
|
||||
abi_ulong target_iov, abi_long iovlen, abi_ulong target_from,
|
||||
abi_ulong fromlen, abi_ulong target_sinfo, abi_ulong target_msgflags)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall sctp_generic_recvmsg()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* sendfile(2) */
|
||||
static inline abi_long do_freebsd_sendfile(abi_long fd, abi_long s,
|
||||
abi_ulong arg3, abi_ulong arg4, abi_ulong nbytes, abi_ulong target_hdtr,
|
||||
abi_ulong target_sbytes, abi_long flags)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall sendfile()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 1000000
|
||||
/* bindat(2) */
|
||||
static inline abi_long do_freebsd_bindat(int fd, int sockfd,
|
||||
abi_ulong target_addr, socklen_t addrlen)
|
||||
{
|
||||
abi_long ret;
|
||||
void *addr;
|
||||
|
||||
if ((int)addrlen < 0) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
|
||||
addr = alloca(addrlen + 1);
|
||||
ret = target_to_host_sockaddr(addr, target_addr, addrlen);
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return get_errno(bindat(fd, sockfd, addr, addrlen));
|
||||
}
|
||||
|
||||
/* connectat(2) */
|
||||
static inline abi_long do_freebsd_connectat(int fd, int sockfd,
|
||||
abi_ulong target_addr, socklen_t addrlen)
|
||||
{
|
||||
abi_long ret;
|
||||
void *addr;
|
||||
|
||||
if ((int)addrlen < 0) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
addr = alloca(addrlen);
|
||||
|
||||
ret = target_to_host_sockaddr(addr, target_addr, addrlen);
|
||||
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return get_errno(connectat(fd, sockfd, addr, addrlen));
|
||||
}
|
||||
|
||||
/* accept4(2) */
|
||||
static inline abi_long do_freebsd_accept4(int fd, abi_ulong target_addr,
|
||||
abi_ulong target_addrlen_addr, int flags)
|
||||
{
|
||||
socklen_t addrlen;
|
||||
void *addr;
|
||||
abi_long ret;
|
||||
|
||||
if (target_addr == 0) {
|
||||
return get_errno(accept(fd, NULL, NULL));
|
||||
}
|
||||
/* return EINVAL if addrlen pointer is invalid */
|
||||
if (get_user_u32(addrlen, target_addrlen_addr)) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
if ((int)addrlen < 0) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
addr = alloca(addrlen);
|
||||
|
||||
ret = get_errno(accept4(fd, addr, &addrlen, flags));
|
||||
if (!is_error(ret)) {
|
||||
host_to_target_sockaddr(target_addr, addr, addrlen);
|
||||
if (put_user_u32(addrlen, target_addrlen_addr)) {
|
||||
ret = -TARGET_EFAULT;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else /* ! __FreeBSD_version >= 1000000 */
|
||||
|
||||
/* bindat(2) */
|
||||
static inline abi_long do_freebsd_bindat(__unused int fd, __unused int sockfd,
|
||||
__unused abi_ulong target_addr, __unused socklen_t addrlen)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall bindat()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* connectat(2) */
|
||||
static inline abi_long do_freebsd_connectat(__unused int fd,
|
||||
__unused int sockfd, __unused abi_ulong target_addr,
|
||||
__unused socklen_t addrlen)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall connectat()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
/* accept4(2) */
|
||||
static inline abi_long do_freebsd_accept4(__unused int fd,
|
||||
__unused abi_ulong target_addr, __unused abi_ulong target_addrlen_addr,
|
||||
__unused int flags)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall accept4()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
#endif /* ! __FreeBSD_version >= 1000000 */
|
||||
#endif /* !__FREEBSD_SOCKET_H_ */
|
|
@ -0,0 +1,336 @@
|
|||
/*
|
||||
* FreeBSD stat related conversion routines
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#define _WANT_FREEBSD11_STAT
|
||||
#define _WANT_FREEBSD11_STATFS
|
||||
#define _WANT_FREEBSD11_DIRENT
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include "qemu.h"
|
||||
#include "qemu-os.h"
|
||||
|
||||
/*
|
||||
* stat conversion
|
||||
*/
|
||||
abi_long h2t_freebsd11_stat(abi_ulong target_addr,
|
||||
struct freebsd11_stat *host_st)
|
||||
{
|
||||
struct target_freebsd11_stat *target_st;
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
memset(target_st, 0, sizeof(*target_st));
|
||||
__put_user(host_st->st_dev, &target_st->st_dev);
|
||||
__put_user(host_st->st_ino, &target_st->st_ino);
|
||||
__put_user(host_st->st_mode, &target_st->st_mode);
|
||||
__put_user(host_st->st_nlink, &target_st->st_nlink);
|
||||
__put_user(host_st->st_uid, &target_st->st_uid);
|
||||
__put_user(host_st->st_gid, &target_st->st_gid);
|
||||
__put_user(host_st->st_rdev, &target_st->st_rdev);
|
||||
__put_user(host_st->st_atim.tv_sec, &target_st->st_atim.tv_sec);
|
||||
__put_user(host_st->st_atim.tv_nsec, &target_st->st_atim.tv_nsec);
|
||||
__put_user(host_st->st_mtim.tv_sec, &target_st->st_mtim.tv_sec);
|
||||
__put_user(host_st->st_mtim.tv_nsec, &target_st->st_mtim.tv_nsec);
|
||||
__put_user(host_st->st_ctim.tv_sec, &target_st->st_ctim.tv_sec);
|
||||
__put_user(host_st->st_ctim.tv_nsec, &target_st->st_ctim.tv_nsec);
|
||||
__put_user(host_st->st_size, &target_st->st_size);
|
||||
__put_user(host_st->st_blocks, &target_st->st_blocks);
|
||||
__put_user(host_st->st_blksize, &target_st->st_blksize);
|
||||
__put_user(host_st->st_flags, &target_st->st_flags);
|
||||
__put_user(host_st->st_gen, &target_st->st_gen);
|
||||
/* st_lspare not used */
|
||||
__put_user(host_st->st_birthtim.tv_sec, &target_st->st_birthtim.tv_sec);
|
||||
__put_user(host_st->st_birthtim.tv_nsec, &target_st->st_birthtim.tv_nsec);
|
||||
unlock_user_struct(target_st, target_addr, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef BSD_HAVE_INO64
|
||||
abi_long h2t_freebsd_stat(abi_ulong target_addr,
|
||||
struct stat *host_st)
|
||||
{
|
||||
struct target_stat *target_st;
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
memset(target_st, 0, sizeof(*target_st));
|
||||
__put_user(host_st->st_dev, &target_st->st_dev);
|
||||
__put_user(host_st->st_ino, &target_st->st_ino);
|
||||
__put_user(host_st->st_nlink, &target_st->st_nlink);
|
||||
__put_user(host_st->st_mode, &target_st->st_mode);
|
||||
__put_user(host_st->st_uid, &target_st->st_uid);
|
||||
__put_user(host_st->st_gid, &target_st->st_gid);
|
||||
__put_user(host_st->st_rdev, &target_st->st_rdev);
|
||||
__put_user(host_st->st_atim.tv_sec, &target_st->st_atim.tv_sec);
|
||||
__put_user(host_st->st_atim.tv_nsec, &target_st->st_atim.tv_nsec);
|
||||
#ifdef __STAT_TIME_T_EXT
|
||||
/* __put_user(host_st->st_mtim_ext, &target_st->st_mtim_ext); XXX */
|
||||
#endif
|
||||
__put_user(host_st->st_mtim.tv_sec, &target_st->st_mtim.tv_sec);
|
||||
__put_user(host_st->st_mtim.tv_nsec, &target_st->st_mtim.tv_nsec);
|
||||
#ifdef __STAT_TIME_T_EXT
|
||||
/* __put_user(host_st->st_ctim_ext, &target_st->st_ctim_ext); XXX */
|
||||
#endif
|
||||
__put_user(host_st->st_ctim.tv_sec, &target_st->st_ctim.tv_sec);
|
||||
__put_user(host_st->st_ctim.tv_nsec, &target_st->st_ctim.tv_nsec);
|
||||
#ifdef __STAT_TIME_T_EXT
|
||||
/* __put_user(host_st->st_birthtim_ext, &target_st->st_birthtim_ext); XXX */
|
||||
#endif
|
||||
__put_user(host_st->st_birthtim.tv_sec, &target_st->st_birthtim.tv_sec);
|
||||
__put_user(host_st->st_birthtim.tv_nsec, &target_st->st_birthtim.tv_nsec);
|
||||
|
||||
__put_user(host_st->st_size, &target_st->st_size);
|
||||
__put_user(host_st->st_blocks, &target_st->st_blocks);
|
||||
__put_user(host_st->st_blksize, &target_st->st_blksize);
|
||||
__put_user(host_st->st_flags, &target_st->st_flags);
|
||||
__put_user(host_st->st_gen, &target_st->st_gen);
|
||||
unlock_user_struct(target_st, target_addr, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
abi_long h2t_freebsd11_nstat(abi_ulong target_addr,
|
||||
struct freebsd11_stat *host_st)
|
||||
{
|
||||
struct target_freebsd11_nstat *target_st;
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
memset(target_st, 0, sizeof(*target_st));
|
||||
__put_user(host_st->st_dev, &target_st->st_dev);
|
||||
__put_user(host_st->st_ino, &target_st->st_ino);
|
||||
__put_user(host_st->st_mode, &target_st->st_mode);
|
||||
__put_user(host_st->st_nlink, &target_st->st_nlink);
|
||||
__put_user(host_st->st_uid, &target_st->st_uid);
|
||||
__put_user(host_st->st_gid, &target_st->st_gid);
|
||||
__put_user(host_st->st_rdev, &target_st->st_rdev);
|
||||
__put_user(host_st->st_atim.tv_sec, &target_st->st_atim.tv_sec);
|
||||
__put_user(host_st->st_atim.tv_nsec, &target_st->st_atim.tv_nsec);
|
||||
__put_user(host_st->st_mtim.tv_sec, &target_st->st_mtim.tv_sec);
|
||||
__put_user(host_st->st_mtim.tv_nsec, &target_st->st_mtim.tv_nsec);
|
||||
__put_user(host_st->st_ctim.tv_sec, &target_st->st_ctim.tv_sec);
|
||||
__put_user(host_st->st_ctim.tv_nsec, &target_st->st_ctim.tv_nsec);
|
||||
__put_user(host_st->st_size, &target_st->st_size);
|
||||
__put_user(host_st->st_blocks, &target_st->st_blocks);
|
||||
__put_user(host_st->st_blksize, &target_st->st_blksize);
|
||||
__put_user(host_st->st_flags, &target_st->st_flags);
|
||||
__put_user(host_st->st_gen, &target_st->st_gen);
|
||||
__put_user(host_st->st_birthtim.tv_sec, &target_st->st_birthtim.tv_sec);
|
||||
__put_user(host_st->st_birthtim.tv_nsec, &target_st->st_birthtim.tv_nsec);
|
||||
unlock_user_struct(target_st, target_addr, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* file handle conversion
|
||||
*/
|
||||
abi_long t2h_freebsd_fhandle(fhandle_t *host_fh, abi_ulong target_addr)
|
||||
{
|
||||
target_freebsd_fhandle_t *target_fh;
|
||||
|
||||
if (!lock_user_struct(VERIFY_READ, target_fh, target_addr, 1)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__get_user(host_fh->fh_fsid.val[0], &target_fh->fh_fsid.val[0]);
|
||||
__get_user(host_fh->fh_fsid.val[1], &target_fh->fh_fsid.val[0]);
|
||||
__get_user(host_fh->fh_fid.fid_len, &target_fh->fh_fid.fid_len);
|
||||
/* u_short fid_data0; */
|
||||
memcpy(host_fh->fh_fid.fid_data, target_fh->fh_fid.fid_data,
|
||||
TARGET_MAXFIDSZ);
|
||||
unlock_user_struct(target_fh, target_addr, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long h2t_freebsd_fhandle(abi_ulong target_addr, fhandle_t *host_fh)
|
||||
{
|
||||
target_freebsd_fhandle_t *target_fh;
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_fh, target_addr, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__put_user(host_fh->fh_fsid.val[0], &target_fh->fh_fsid.val[0]);
|
||||
__put_user(host_fh->fh_fsid.val[1], &target_fh->fh_fsid.val[0]);
|
||||
__put_user(host_fh->fh_fid.fid_len, &target_fh->fh_fid.fid_len);
|
||||
/* u_short fid_data0; */
|
||||
memcpy(target_fh->fh_fid.fid_data, host_fh->fh_fid.fid_data,
|
||||
TARGET_MAXFIDSZ);
|
||||
unlock_user_struct(target_fh, target_addr, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* file system stat
|
||||
*/
|
||||
abi_long h2t_freebsd11_statfs(abi_ulong target_addr,
|
||||
struct freebsd11_statfs *host_statfs)
|
||||
{
|
||||
struct target_freebsd11_statfs *target_statfs;
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_statfs, target_addr, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__put_user(host_statfs->f_version, &target_statfs->f_version);
|
||||
__put_user(host_statfs->f_type, &target_statfs->f_type);
|
||||
__put_user(host_statfs->f_flags, &target_statfs->f_flags);
|
||||
__put_user(host_statfs->f_bsize, &target_statfs->f_bsize);
|
||||
__put_user(host_statfs->f_iosize, &target_statfs->f_iosize);
|
||||
__put_user(host_statfs->f_blocks, &target_statfs->f_blocks);
|
||||
__put_user(host_statfs->f_bfree, &target_statfs->f_bfree);
|
||||
__put_user(host_statfs->f_bavail, &target_statfs->f_bavail);
|
||||
__put_user(host_statfs->f_files, &target_statfs->f_files);
|
||||
__put_user(host_statfs->f_ffree, &target_statfs->f_ffree);
|
||||
__put_user(host_statfs->f_syncwrites, &target_statfs->f_syncwrites);
|
||||
__put_user(host_statfs->f_asyncwrites, &target_statfs->f_asyncwrites);
|
||||
__put_user(host_statfs->f_syncreads, &target_statfs->f_syncreads);
|
||||
__put_user(host_statfs->f_asyncreads, &target_statfs->f_asyncreads);
|
||||
/* uint64_t f_spare[10]; */
|
||||
__put_user(host_statfs->f_namemax, &target_statfs->f_namemax);
|
||||
__put_user(host_statfs->f_owner, &target_statfs->f_owner);
|
||||
__put_user(host_statfs->f_fsid.val[0], &target_statfs->f_fsid.val[0]);
|
||||
__put_user(host_statfs->f_fsid.val[1], &target_statfs->f_fsid.val[1]);
|
||||
/* char f_charspace[80]; */
|
||||
strncpy(target_statfs->f_fstypename, host_statfs->f_fstypename,
|
||||
sizeof(target_statfs->f_fstypename));
|
||||
strncpy(target_statfs->f_mntfromname, host_statfs->f_mntfromname,
|
||||
sizeof(target_statfs->f_mntfromname));
|
||||
strncpy(target_statfs->f_mntonname, host_statfs->f_mntonname,
|
||||
sizeof(target_statfs->f_mntonname));
|
||||
unlock_user_struct(target_statfs, target_addr, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef BSD_HAVE_INO64
|
||||
abi_long h2t_freebsd_statfs(abi_ulong target_addr,
|
||||
struct statfs *host_statfs)
|
||||
{
|
||||
struct target_statfs *target_statfs;
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_statfs, target_addr, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__put_user(host_statfs->f_version, &target_statfs->f_version);
|
||||
__put_user(host_statfs->f_type, &target_statfs->f_type);
|
||||
__put_user(host_statfs->f_flags, &target_statfs->f_flags);
|
||||
__put_user(host_statfs->f_bsize, &target_statfs->f_bsize);
|
||||
__put_user(host_statfs->f_iosize, &target_statfs->f_iosize);
|
||||
__put_user(host_statfs->f_blocks, &target_statfs->f_blocks);
|
||||
__put_user(host_statfs->f_bfree, &target_statfs->f_bfree);
|
||||
__put_user(host_statfs->f_bavail, &target_statfs->f_bavail);
|
||||
__put_user(host_statfs->f_files, &target_statfs->f_files);
|
||||
__put_user(host_statfs->f_ffree, &target_statfs->f_ffree);
|
||||
__put_user(host_statfs->f_syncwrites, &target_statfs->f_syncwrites);
|
||||
__put_user(host_statfs->f_asyncwrites, &target_statfs->f_asyncwrites);
|
||||
__put_user(host_statfs->f_syncreads, &target_statfs->f_syncreads);
|
||||
__put_user(host_statfs->f_asyncreads, &target_statfs->f_asyncreads);
|
||||
/* uint64_t f_spare[10]; */
|
||||
__put_user(host_statfs->f_namemax, &target_statfs->f_namemax);
|
||||
__put_user(host_statfs->f_owner, &target_statfs->f_owner);
|
||||
__put_user(host_statfs->f_fsid.val[0], &target_statfs->f_fsid.val[0]);
|
||||
__put_user(host_statfs->f_fsid.val[1], &target_statfs->f_fsid.val[1]);
|
||||
/* char f_charspace[80]; */
|
||||
strncpy(target_statfs->f_fstypename, host_statfs->f_fstypename,
|
||||
sizeof(target_statfs->f_fstypename));
|
||||
strncpy(target_statfs->f_mntfromname, host_statfs->f_mntfromname,
|
||||
sizeof(target_statfs->f_mntfromname));
|
||||
strncpy(target_statfs->f_mntonname, host_statfs->f_mntonname,
|
||||
sizeof(target_statfs->f_mntonname));
|
||||
unlock_user_struct(target_statfs, target_addr, 1);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* fcntl cmd conversion
|
||||
*/
|
||||
abi_long target_to_host_fcntl_cmd(int cmd)
|
||||
{
|
||||
|
||||
switch (cmd) {
|
||||
case TARGET_F_DUPFD:
|
||||
return F_DUPFD;
|
||||
|
||||
case TARGET_F_DUP2FD:
|
||||
return F_DUP2FD;
|
||||
|
||||
case TARGET_F_GETFD:
|
||||
return F_GETFD;
|
||||
|
||||
case TARGET_F_SETFD:
|
||||
return F_SETFD;
|
||||
|
||||
case TARGET_F_GETFL:
|
||||
return F_GETFL;
|
||||
|
||||
case TARGET_F_SETFL:
|
||||
return F_SETFL;
|
||||
|
||||
case TARGET_F_GETOWN:
|
||||
return F_GETOWN;
|
||||
|
||||
case TARGET_F_SETOWN:
|
||||
return F_SETOWN;
|
||||
|
||||
case TARGET_F_GETLK:
|
||||
return F_GETLK;
|
||||
|
||||
case TARGET_F_SETLK:
|
||||
return F_SETLK;
|
||||
|
||||
case TARGET_F_SETLKW:
|
||||
return F_SETLKW;
|
||||
|
||||
case TARGET_F_READAHEAD:
|
||||
return F_READAHEAD;
|
||||
|
||||
case TARGET_F_RDAHEAD:
|
||||
return F_RDAHEAD;
|
||||
|
||||
#ifdef F_DUPFD_CLOEXEC
|
||||
case TARGET_F_DUPFD_CLOEXEC:
|
||||
return F_DUPFD_CLOEXEC;
|
||||
#endif
|
||||
|
||||
#ifdef F_DUP2FD_CLOEXEC
|
||||
case TARGET_F_DUP2FD_CLOEXEC:
|
||||
return F_DUP2FD_CLOEXEC;
|
||||
#endif
|
||||
|
||||
#ifdef F_ADD_SEALS
|
||||
case TARGET_F_ADD_SEALS:
|
||||
return F_ADD_SEALS;
|
||||
#endif
|
||||
|
||||
#ifdef F_GET_SEALS
|
||||
case TARGET_F_GET_SEALS:
|
||||
return F_GET_SEALS;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,713 @@
|
|||
/*
|
||||
* stat 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 __FREEBSD_STAT_H_
|
||||
#define __FREEBSD_STAT_H_
|
||||
|
||||
#define _WANT_FREEBSD11_STAT
|
||||
#define _WANT_FREEBSD11_STATFS
|
||||
#define _WANT_FREEBSD11_DIRENT
|
||||
#include <sys/types.h>
|
||||
#include <sys/ucred.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "qemu-os.h"
|
||||
|
||||
#ifndef BSD_HAVE_INO64
|
||||
#define freebsd11_dirent dirent
|
||||
|
||||
#define freebsd11_stat stat
|
||||
#define freebsd11_lstat lstat
|
||||
#define freebsd11_fstat fstat
|
||||
#define freebsd11_fstatat fstatat
|
||||
#define freebsd11_nstat nstat
|
||||
#define freebsd11_nfstat nfstat
|
||||
#define freebsd11_nlstat nlstat
|
||||
#define freebsd11_fhstat fhstat
|
||||
#define freebsd11_fhstatfs fhstatfs
|
||||
#define freebsd11_statfs statfs
|
||||
#define freebsd11_fstatfs fstatfs
|
||||
#define freebsd11_getfsstat getfsstat
|
||||
#define freebsd11_getdents getdents
|
||||
#define freebsd11_getdirentries getdirentries
|
||||
|
||||
/* undocumented nstat system calls */
|
||||
int nstat(const char *path, struct stat *sb);
|
||||
int nlstat(const char *path, struct stat *sb);
|
||||
int nfstat(int fd, struct stat *sb);
|
||||
#else
|
||||
int freebsd11_stat(const char *path, struct freebsd11_stat *stat);
|
||||
__sym_compat(stat, freebsd11_stat, FBSD_1.0);
|
||||
int freebsd11_lstat(const char *path, struct freebsd11_stat *stat);
|
||||
__sym_compat(lstat, freebsd11_lstat, FBSD_1.0);
|
||||
int freebsd11_fstat(int fd, struct freebsd11_stat *stat);
|
||||
__sym_compat(fstat, freebsd11_fstat, FBSD_1.0);
|
||||
int freebsd11_fstatat(int fd, const char *path, struct freebsd11_stat *stat,
|
||||
int flag);
|
||||
__sym_compat(fstatat, freebsd11_fstatat, FBSD_1.1);
|
||||
|
||||
int freebsd11_fhstat(const fhandle_t *fhandle, struct freebsd11_stat *stat);
|
||||
__sym_compat(fhstat, freebsd11_fhstat, FBSD_1.0);
|
||||
int freebsd11_getfsstat(struct freebsd11_statfs *buf, long bufsize, int mode);
|
||||
__sym_compat(getfsstat, freebsd11_getfsstat, FBSD_1.0);
|
||||
int freebsd11_fhstatfs(const fhandle_t *fhandle, struct freebsd11_statfs * buf);
|
||||
__sym_compat(fhstatfs, freebsd11_fhstatfs, FBSD_1.0);
|
||||
int freebsd11_statfs(const char *path, struct freebsd11_statfs *buf);
|
||||
__sym_compat(statfs, freebsd11_statfs, FBSD_1.0);
|
||||
int freebsd11_fstatfs(int fd, struct freebsd11_statfs *buf);
|
||||
__sym_compat(fstatfs, freebsd11_fstatfs, FBSD_1.0);
|
||||
|
||||
ssize_t freebsd11_getdirentries(int fd, char *buf, size_t nbytes, off_t *basep);
|
||||
__sym_compat(getdirentries, freebsd11_getdirentries, FBSD_1.0);
|
||||
ssize_t freebsd11_getdents(int fd, char *buf, size_t nbytes);
|
||||
__sym_compat(getdents, freebsd11_getdents, FBSD_1.0);
|
||||
|
||||
/* undocumented nstat system calls */
|
||||
int freebsd11_nstat(const char *path, struct freebsd11_stat *sb);
|
||||
__sym_compat(nstat, freebsd11_nstat, FBSD_1.0);
|
||||
int freebsd11_nlstat(const char *path, struct freebsd11_stat *sb);
|
||||
__sym_compat(nlstat, freebsd11_nlstat, FBSD_1.0);
|
||||
int freebsd11_nfstat(int fd, struct freebsd11_stat *sb);
|
||||
__sym_compat(nfstat, freebsd11_nfstat, FBSD_1.0);
|
||||
#endif
|
||||
|
||||
/* stat(2) */
|
||||
static inline abi_long do_freebsd11_stat(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
struct freebsd11_stat st;
|
||||
|
||||
LOCK_PATH(p, arg1);
|
||||
ret = get_errno(freebsd11_stat(path(p), &st));
|
||||
UNLOCK_PATH(p, arg1);
|
||||
if (!is_error(ret)) {
|
||||
ret = h2t_freebsd11_stat(arg2, &st);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* lstat(2) */
|
||||
static inline abi_long do_freebsd11_lstat(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
struct freebsd11_stat st;
|
||||
|
||||
LOCK_PATH(p, arg1);
|
||||
ret = get_errno(freebsd11_lstat(path(p), &st));
|
||||
UNLOCK_PATH(p, arg1);
|
||||
if (!is_error(ret)) {
|
||||
ret = h2t_freebsd11_stat(arg2, &st);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* fstat(2) */
|
||||
static inline abi_long do_freebsd11_fstat(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
struct freebsd11_stat st;
|
||||
|
||||
ret = get_errno(freebsd11_fstat(arg1, &st));
|
||||
if (!is_error(ret)) {
|
||||
ret = h2t_freebsd11_stat(arg2, &st);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef BSD_HAVE_INO64
|
||||
/* fstat(2) */
|
||||
static inline abi_long do_freebsd_fstat(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
struct stat st;
|
||||
|
||||
ret = get_errno(fstat(arg1, &st));
|
||||
if (!is_error(ret)) {
|
||||
ret = h2t_freebsd_stat(arg2, &st);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* fstatat(2) */
|
||||
static inline abi_long do_freebsd11_fstatat(abi_long arg1, abi_long arg2,
|
||||
abi_long arg3, abi_long arg4)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
struct freebsd11_stat st;
|
||||
|
||||
LOCK_PATH(p, arg2);
|
||||
ret = get_errno(freebsd11_fstatat(arg1, p, &st, arg4));
|
||||
UNLOCK_PATH(p, arg2);
|
||||
if (!is_error(ret) && arg3) {
|
||||
ret = h2t_freebsd11_stat(arg3, &st);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef BSD_HAVE_INO64
|
||||
/* fstatat(2) */
|
||||
static inline abi_long do_freebsd_fstatat(abi_long arg1, abi_long arg2,
|
||||
abi_long arg3, abi_long arg4)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
struct stat st;
|
||||
|
||||
LOCK_PATH(p, arg2);
|
||||
ret = get_errno(fstatat(arg1, p, &st, arg4));
|
||||
UNLOCK_PATH(p, arg2);
|
||||
if (!is_error(ret) && arg3) {
|
||||
ret = h2t_freebsd_stat(arg3, &st);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* undocummented nstat(char *path, struct nstat *ub) syscall */
|
||||
static abi_long do_freebsd11_nstat(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
struct freebsd11_stat st;
|
||||
|
||||
LOCK_PATH(p, arg1);
|
||||
ret = get_errno(freebsd11_nstat(path(p), &st));
|
||||
UNLOCK_PATH(p, arg1);
|
||||
if (!is_error(ret)) {
|
||||
ret = h2t_freebsd11_nstat(arg2, &st);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* undocummented nfstat(int fd, struct nstat *sb) syscall */
|
||||
static abi_long do_freebsd11_nfstat(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
struct freebsd11_stat st;
|
||||
|
||||
ret = get_errno(freebsd11_nfstat(arg1, &st));
|
||||
if (!is_error(ret)) {
|
||||
ret = h2t_freebsd11_nstat(arg2, &st);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* undocummented nlstat(char *path, struct nstat *ub) syscall */
|
||||
static abi_long do_freebsd11_nlstat(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
struct freebsd11_stat st;
|
||||
|
||||
LOCK_PATH(p, arg1);
|
||||
ret = get_errno(freebsd11_nlstat(path(p), &st));
|
||||
UNLOCK_PATH(p, arg1);
|
||||
if (!is_error(ret)) {
|
||||
ret = h2t_freebsd11_nstat(arg2, &st);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* getfh(2) */
|
||||
static abi_long do_freebsd_getfh(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
fhandle_t host_fh;
|
||||
|
||||
LOCK_PATH(p, arg1);
|
||||
ret = get_errno(getfh(path(p), &host_fh));
|
||||
UNLOCK_PATH(p, arg1);
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
return h2t_freebsd_fhandle(arg2, &host_fh);
|
||||
}
|
||||
|
||||
/* lgetfh(2) */
|
||||
static inline abi_long do_freebsd_lgetfh(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
fhandle_t host_fh;
|
||||
|
||||
LOCK_PATH(p, arg1);
|
||||
ret = get_errno(lgetfh(path(p), &host_fh));
|
||||
UNLOCK_PATH(p, arg1);
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
return h2t_freebsd_fhandle(arg2, &host_fh);
|
||||
}
|
||||
|
||||
/* fhopen(2) */
|
||||
static inline abi_long do_freebsd_fhopen(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
fhandle_t host_fh;
|
||||
|
||||
ret = t2h_freebsd_fhandle(&host_fh, arg1);
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return get_errno(fhopen(&host_fh, arg2));
|
||||
}
|
||||
|
||||
/* fhstat(2) */
|
||||
static inline abi_long do_freebsd11_fhstat(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
fhandle_t host_fh;
|
||||
struct freebsd11_stat host_sb;
|
||||
|
||||
ret = t2h_freebsd_fhandle(&host_fh, arg1);
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
ret = get_errno(freebsd11_fhstat(&host_fh, &host_sb));
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
return h2t_freebsd11_stat(arg2, &host_sb);
|
||||
}
|
||||
|
||||
#ifdef BSD_HAVE_INO64
|
||||
/* fhstat(2) */
|
||||
static inline abi_long do_freebsd_fhstat(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
fhandle_t host_fh;
|
||||
struct stat host_sb;
|
||||
|
||||
ret = t2h_freebsd_fhandle(&host_fh, arg1);
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
ret = get_errno(fhstat(&host_fh, &host_sb));
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
return h2t_freebsd_stat(arg2, &host_sb);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* fhstatfs(2) */
|
||||
static inline abi_long do_freebsd11_fhstatfs(abi_ulong target_fhp_addr,
|
||||
abi_ulong target_stfs_addr)
|
||||
{
|
||||
abi_long ret;
|
||||
fhandle_t host_fh;
|
||||
struct freebsd11_statfs host_stfs;
|
||||
|
||||
ret = t2h_freebsd_fhandle(&host_fh, target_fhp_addr);
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
ret = get_errno(freebsd11_fhstatfs(&host_fh, &host_stfs));
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
return h2t_freebsd11_statfs(target_stfs_addr, &host_stfs);
|
||||
}
|
||||
|
||||
#ifdef BSD_HAVE_INO64
|
||||
/* fhstatfs(2) */
|
||||
static inline abi_long do_freebsd_fhstatfs(abi_ulong target_fhp_addr,
|
||||
abi_ulong target_stfs_addr)
|
||||
{
|
||||
abi_long ret;
|
||||
fhandle_t host_fh;
|
||||
struct statfs host_stfs;
|
||||
|
||||
ret = t2h_freebsd_fhandle(&host_fh, target_fhp_addr);
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
ret = get_errno(fhstatfs(&host_fh, &host_stfs));
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
return h2t_freebsd_statfs(target_stfs_addr, &host_stfs);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* statfs(2) */
|
||||
static inline abi_long do_freebsd11_statfs(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
struct freebsd11_statfs host_stfs;
|
||||
|
||||
LOCK_PATH(p, arg1);
|
||||
ret = get_errno(freebsd11_statfs(path(p), &host_stfs));
|
||||
UNLOCK_PATH(p, arg1);
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return h2t_freebsd11_statfs(arg2, &host_stfs);
|
||||
}
|
||||
|
||||
#ifdef BSD_HAVE_INO64
|
||||
/* statfs(2) */
|
||||
static inline abi_long do_freebsd_statfs(abi_long arg1, abi_long arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
struct statfs host_stfs;
|
||||
|
||||
LOCK_PATH(p, arg1);
|
||||
ret = get_errno(statfs(path(p), &host_stfs));
|
||||
UNLOCK_PATH(p, arg1);
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return h2t_freebsd_statfs(arg2, &host_stfs);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* fstatfs(2) */
|
||||
static inline abi_long do_freebsd11_fstatfs(abi_long fd, abi_ulong target_addr)
|
||||
{
|
||||
abi_long ret;
|
||||
struct freebsd11_statfs host_stfs;
|
||||
|
||||
ret = get_errno(freebsd11_fstatfs(fd, &host_stfs));
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return h2t_freebsd11_statfs(target_addr, &host_stfs);
|
||||
}
|
||||
#ifdef BSD_HAVE_INO64
|
||||
/* fstatfs(2) */
|
||||
static inline abi_long do_freebsd_fstatfs(abi_long fd, abi_ulong target_addr)
|
||||
{
|
||||
abi_long ret;
|
||||
struct statfs host_stfs;
|
||||
|
||||
ret = get_errno(fstatfs(fd, &host_stfs));
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return h2t_freebsd_statfs(target_addr, &host_stfs);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* getfsstat(2) */
|
||||
static inline abi_long do_freebsd11_getfsstat(abi_ulong target_addr,
|
||||
abi_long bufsize, abi_long flags)
|
||||
{
|
||||
abi_long ret;
|
||||
struct freebsd11_statfs *host_stfs;
|
||||
int count;
|
||||
long host_bufsize;
|
||||
|
||||
count = bufsize / sizeof(struct target_freebsd11_statfs);
|
||||
|
||||
/* if user buffer is NULL then return number of mounted FS's */
|
||||
if (target_addr == 0 || count == 0) {
|
||||
return get_errno(freebsd11_getfsstat(NULL, 0, flags));
|
||||
}
|
||||
|
||||
/* XXX check count to be reasonable */
|
||||
host_bufsize = sizeof(struct freebsd11_statfs) * count;
|
||||
host_stfs = alloca(host_bufsize);
|
||||
if (!host_stfs) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
|
||||
ret = count = get_errno(freebsd11_getfsstat(host_stfs, host_bufsize, flags));
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (count--) {
|
||||
if (h2t_freebsd11_statfs((target_addr +
|
||||
(count * sizeof(struct target_freebsd11_statfs))),
|
||||
&host_stfs[count])) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef BSD_HAVE_INO64
|
||||
/* getfsstat(2) */
|
||||
static inline abi_long do_freebsd_getfsstat(abi_ulong target_addr,
|
||||
abi_long bufsize, abi_long flags)
|
||||
{
|
||||
abi_long ret;
|
||||
struct statfs *host_stfs;
|
||||
int count;
|
||||
long host_bufsize;
|
||||
|
||||
count = bufsize / sizeof(struct target_statfs);
|
||||
|
||||
/* if user buffer is NULL then return number of mounted FS's */
|
||||
if (target_addr == 0 || count == 0) {
|
||||
return get_errno(freebsd11_getfsstat(NULL, 0, flags));
|
||||
}
|
||||
|
||||
/* XXX check count to be reasonable */
|
||||
host_bufsize = sizeof(struct statfs) * count;
|
||||
host_stfs = alloca(host_bufsize);
|
||||
if (!host_stfs) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
|
||||
ret = count = get_errno(getfsstat(host_stfs, host_bufsize, flags));
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (count--) {
|
||||
if (h2t_freebsd_statfs((target_addr +
|
||||
(count * sizeof(struct target_statfs))),
|
||||
&host_stfs[count])) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* getdents(2) */
|
||||
static inline abi_long do_freebsd11_getdents(abi_long arg1,
|
||||
abi_ulong arg2, abi_long nbytes)
|
||||
{
|
||||
abi_long ret;
|
||||
struct freebsd11_dirent *dirp;
|
||||
|
||||
dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0);
|
||||
if (dirp == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(freebsd11_getdents(arg1, (char *)dirp, nbytes));
|
||||
if (!is_error(ret)) {
|
||||
struct freebsd11_dirent *de;
|
||||
int len = ret;
|
||||
int reclen;
|
||||
|
||||
de = dirp;
|
||||
while (len > 0) {
|
||||
reclen = de->d_reclen;
|
||||
if (reclen > len) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
de->d_reclen = tswap16(reclen);
|
||||
de->d_fileno = tswap32(de->d_fileno);
|
||||
len -= reclen;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* getdirecentries(2) */
|
||||
static inline abi_long do_freebsd11_getdirentries(abi_long arg1,
|
||||
abi_ulong arg2, abi_long nbytes, abi_ulong arg4)
|
||||
{
|
||||
abi_long ret;
|
||||
struct freebsd11_dirent *dirp;
|
||||
long basep;
|
||||
|
||||
dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0);
|
||||
if (dirp == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(freebsd11_getdirentries(arg1, (char *)dirp, nbytes, &basep));
|
||||
if (!is_error(ret)) {
|
||||
struct freebsd11_dirent *de;
|
||||
int len = ret;
|
||||
int reclen;
|
||||
|
||||
de = dirp;
|
||||
while (len > 0) {
|
||||
reclen = de->d_reclen;
|
||||
if (reclen > len) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
de->d_reclen = tswap16(reclen);
|
||||
de->d_fileno = tswap32(de->d_fileno);
|
||||
len -= reclen;
|
||||
de = (struct freebsd11_dirent *)((void *)de + reclen);
|
||||
}
|
||||
}
|
||||
unlock_user(dirp, arg2, ret);
|
||||
if (arg4) {
|
||||
if (put_user(basep, arg4, abi_ulong)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef BSD_HAVE_INO64
|
||||
/* getdirecentries(2) */
|
||||
static inline abi_long do_freebsd_getdirentries(abi_long arg1,
|
||||
abi_ulong arg2, abi_long nbytes, abi_ulong arg4)
|
||||
{
|
||||
abi_long ret;
|
||||
struct dirent *dirp;
|
||||
long basep;
|
||||
|
||||
dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0);
|
||||
if (dirp == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(getdirentries(arg1, (char *)dirp, nbytes, &basep));
|
||||
if (!is_error(ret)) {
|
||||
struct dirent *de;
|
||||
int len = ret;
|
||||
int reclen;
|
||||
|
||||
de = dirp;
|
||||
while (len > 0) {
|
||||
reclen = de->d_reclen;
|
||||
if (reclen > len) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
de->d_fileno = tswap64(de->d_fileno);
|
||||
de->d_off = tswap64(de->d_off);
|
||||
de->d_reclen = tswap16(de->d_reclen);
|
||||
de->d_namlen = tswap16(de->d_namlen);
|
||||
len -= reclen;
|
||||
de = (struct dirent *)((void *)de + reclen);
|
||||
}
|
||||
}
|
||||
unlock_user(dirp, arg2, ret);
|
||||
if (arg4) {
|
||||
if (put_user(basep, arg4, abi_ulong)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* fcntl(2) */
|
||||
static inline abi_long do_freebsd_fcntl(abi_long arg1, abi_long arg2,
|
||||
abi_ulong arg3)
|
||||
{
|
||||
abi_long ret;
|
||||
int host_cmd;
|
||||
struct flock fl;
|
||||
struct target_freebsd_flock *target_fl;
|
||||
|
||||
host_cmd = target_to_host_fcntl_cmd(arg2);
|
||||
if (host_cmd < 0) {
|
||||
return host_cmd;
|
||||
}
|
||||
switch (arg2) {
|
||||
case TARGET_F_GETLK:
|
||||
if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__get_user(fl.l_type, &target_fl->l_type);
|
||||
__get_user(fl.l_whence, &target_fl->l_whence);
|
||||
__get_user(fl.l_start, &target_fl->l_start);
|
||||
__get_user(fl.l_len, &target_fl->l_len);
|
||||
__get_user(fl.l_pid, &target_fl->l_pid);
|
||||
__get_user(fl.l_sysid, &target_fl->l_sysid);
|
||||
unlock_user_struct(target_fl, arg3, 0);
|
||||
ret = get_errno(safe_fcntl(arg1, host_cmd, &fl));
|
||||
if (!is_error(ret)) {
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__put_user(fl.l_type, &target_fl->l_type);
|
||||
__put_user(fl.l_whence, &target_fl->l_whence);
|
||||
__put_user(fl.l_start, &target_fl->l_start);
|
||||
__put_user(fl.l_len, &target_fl->l_len);
|
||||
__put_user(fl.l_pid, &target_fl->l_pid);
|
||||
__put_user(fl.l_sysid, &target_fl->l_sysid);
|
||||
unlock_user_struct(target_fl, arg3, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case TARGET_F_SETLK:
|
||||
case TARGET_F_SETLKW:
|
||||
if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__get_user(fl.l_type, &target_fl->l_type);
|
||||
__get_user(fl.l_whence, &target_fl->l_whence);
|
||||
__get_user(fl.l_start, &target_fl->l_start);
|
||||
__get_user(fl.l_len, &target_fl->l_len);
|
||||
__get_user(fl.l_pid, &target_fl->l_pid);
|
||||
__get_user(fl.l_sysid, &target_fl->l_sysid);
|
||||
unlock_user_struct(target_fl, arg3, 0);
|
||||
ret = get_errno(safe_fcntl(arg1, host_cmd, &fl));
|
||||
break;
|
||||
|
||||
case TARGET_F_DUPFD:
|
||||
case TARGET_F_DUP2FD:
|
||||
case TARGET_F_GETOWN:
|
||||
case TARGET_F_SETOWN:
|
||||
case TARGET_F_GETFD:
|
||||
case TARGET_F_SETFD:
|
||||
case TARGET_F_GETFL:
|
||||
case TARGET_F_SETFL:
|
||||
case TARGET_F_READAHEAD:
|
||||
case TARGET_F_RDAHEAD:
|
||||
case TARGET_F_ADD_SEALS:
|
||||
case TARGET_F_GET_SEALS:
|
||||
default:
|
||||
ret = get_errno(safe_fcntl(arg1, host_cmd, arg3));
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 1300080
|
||||
extern int __realpathat(int fd, const char *path, char *buf, size_t size,
|
||||
int flags);
|
||||
// https://svnweb.freebsd.org/base?view=revision&revision=358172
|
||||
// no man page
|
||||
static inline abi_long do_freebsd_realpathat(abi_long arg1, abi_long arg2,
|
||||
abi_long arg3, abi_long arg4, abi_long arg5)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p, *b;
|
||||
|
||||
LOCK_PATH(p, arg2);
|
||||
b = lock_user(VERIFY_WRITE, arg3, arg4, 0);
|
||||
if (b == NULL) {
|
||||
UNLOCK_PATH(p, arg2);
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
|
||||
ret = get_errno(__realpathat(arg1, p, b, arg4, arg5));
|
||||
UNLOCK_PATH(p, arg2);
|
||||
unlock_user(b, arg3, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ! __FREEBSD_STAT_H_ */
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,645 @@
|
|||
/*
|
||||
* FreeBSD thread and user mutex related system call shims
|
||||
*
|
||||
* Copyright (c) 2013-15 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 __FREEBSD_OS_THREAD_H_
|
||||
#define __FREEBSD_OS_THREAD_H_
|
||||
|
||||
#include <sys/thr.h>
|
||||
#include <sys/rtprio.h>
|
||||
#include <sys/umtx.h>
|
||||
|
||||
#include "qemu.h"
|
||||
#include "qemu-os.h"
|
||||
|
||||
int safe_thr_suspend(struct timespec *timeout);
|
||||
int safe__umtx_op(void *, int, unsigned long, void *, void *);
|
||||
|
||||
#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) && \
|
||||
(TARGET_ABI_BITS == HOST_LONG_BITS || defined(UMTX_OP__32BIT))
|
||||
#define _UMTX_OPTIMIZED
|
||||
#if defined(TARGET_ABI32)
|
||||
#define QEMU_UMTX_OP(n) (UMTX_OP__32BIT | (n))
|
||||
#else
|
||||
#define QEMU_UMTX_OP(n) (n)
|
||||
#endif /* TARGET_ABI32 */
|
||||
#else
|
||||
#define QEMU_UMTX_OP(n) (n)
|
||||
#endif
|
||||
|
||||
static inline abi_long do_freebsd_thr_create(CPUArchState *env,
|
||||
abi_ulong target_ctx, abi_ulong target_id, int flags)
|
||||
{
|
||||
|
||||
qemu_log("qemu: Unsupported syscall thr_create()\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
static inline abi_long do_freebsd_thr_self(abi_ulong target_id)
|
||||
{
|
||||
abi_long ret;
|
||||
long tid;
|
||||
|
||||
ret = get_errno(thr_self(&tid));
|
||||
if (!is_error(ret)) {
|
||||
if (put_user_sal(tid, target_id)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline abi_long do_freebsd_thr_exit(CPUArchState *cpu_env,
|
||||
abi_ulong tid_addr)
|
||||
{
|
||||
CPUState *cpu = env_cpu(cpu_env);
|
||||
TaskState *ts;
|
||||
|
||||
/*
|
||||
* XXX This probably breaks if a signal arrives.
|
||||
* We should disable signals.
|
||||
*/
|
||||
cpu_list_lock();
|
||||
/* Remove the CPU from the list. */
|
||||
QTAILQ_REMOVE_RCU(&cpus, cpu, node);
|
||||
cpu_list_unlock();
|
||||
if (tid_addr) {
|
||||
/* Signal target userland that it can free the stack. */
|
||||
if (!put_user_sal(1, tid_addr)) {
|
||||
freebsd_umtx_wake(tid_addr, INT_MAX);
|
||||
}
|
||||
}
|
||||
thread_cpu = NULL;
|
||||
object_unref(OBJECT(env_cpu(cpu_env)));
|
||||
ts = cpu->opaque;
|
||||
g_free(ts);
|
||||
rcu_unregister_thread();
|
||||
pthread_exit(NULL);
|
||||
/* Doesn't return */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline abi_long do_freebsd_thr_kill(long id, int sig)
|
||||
{
|
||||
|
||||
return get_errno(thr_kill(id, target_to_host_signal(sig)));
|
||||
}
|
||||
|
||||
static inline abi_long do_freebsd_thr_kill2(pid_t pid, long id, int sig)
|
||||
{
|
||||
|
||||
return get_errno(thr_kill2(pid, id, target_to_host_signal(sig)));
|
||||
}
|
||||
|
||||
static inline abi_long do_freebsd_thr_suspend(abi_ulong target_ts)
|
||||
{
|
||||
abi_long ret;
|
||||
struct timespec ts;
|
||||
|
||||
if (target_ts != 0) {
|
||||
if (t2h_freebsd_timespec(&ts, target_ts)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(safe_thr_suspend(&ts));
|
||||
} else {
|
||||
ret = get_errno(safe_thr_suspend(NULL));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline abi_long do_freebsd_thr_wake(long tid)
|
||||
{
|
||||
|
||||
return get_errno(thr_wake(tid));
|
||||
}
|
||||
|
||||
static inline abi_long do_freebsd_thr_set_name(long tid, abi_ulong target_name)
|
||||
{
|
||||
abi_long ret;
|
||||
void *p;
|
||||
|
||||
p = lock_user_string(target_name);
|
||||
if (p == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = thr_set_name(tid, p);
|
||||
unlock_user(p, target_name, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline abi_long do_freebsd_rtprio_thread(int function, lwpid_t lwpid,
|
||||
abi_ulong target_addr)
|
||||
{
|
||||
int ret;
|
||||
struct rtprio rtp;
|
||||
|
||||
ret = t2h_freebsd_rtprio(&rtp, target_addr);
|
||||
if (!is_error(ret)) {
|
||||
ret = get_errno(rtprio_thread(function, lwpid, &rtp));
|
||||
}
|
||||
if (!is_error(ret)) {
|
||||
ret = h2t_freebsd_rtprio(target_addr, &rtp);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline abi_long do_freebsd_getcontext(void *cpu_env, abi_ulong arg1)
|
||||
{
|
||||
abi_long ret;
|
||||
target_ucontext_t *ucp;
|
||||
sigset_t sigmask;
|
||||
|
||||
if (arg1 == 0) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
ret = get_errno(sigprocmask(0, NULL, &sigmask));
|
||||
if (!is_error(ret)) {
|
||||
ucp = lock_user(VERIFY_WRITE, arg1, sizeof(target_ucontext_t), 0);
|
||||
if (ucp == 0) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_mcontext(cpu_env, &ucp->uc_mcontext, TARGET_MC_GET_CLEAR_RET);
|
||||
host_to_target_sigset(&ucp->uc_sigmask, &sigmask);
|
||||
memset(ucp->__spare__, 0, sizeof(ucp->__spare__));
|
||||
unlock_user(ucp, arg1, sizeof(target_ucontext_t));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline abi_long do_freebsd_setcontext(void *cpu_env, abi_ulong arg1)
|
||||
{
|
||||
abi_long ret;
|
||||
target_ucontext_t *ucp;
|
||||
sigset_t sigmask;
|
||||
if (arg1 == 0) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
ucp = lock_user(VERIFY_READ, arg1, sizeof(target_ucontext_t), 1);
|
||||
if (ucp == 0) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = set_mcontext(cpu_env, &ucp->uc_mcontext, 0);
|
||||
target_to_host_sigset(&sigmask, &ucp->uc_sigmask);
|
||||
unlock_user(ucp, arg1, sizeof(target_ucontext_t));
|
||||
if (!is_error(ret)) {
|
||||
(void)sigprocmask(SIG_SETMASK, &sigmask, NULL);
|
||||
}
|
||||
return ret == 0 ? -TARGET_EJUSTRETURN : ret;
|
||||
}
|
||||
|
||||
/* swapcontext(2) */
|
||||
static inline abi_long do_freebsd_swapcontext(void *cpu_env, abi_ulong arg1,
|
||||
abi_ulong arg2)
|
||||
{
|
||||
abi_long ret;
|
||||
target_ucontext_t *ucp;
|
||||
sigset_t sigmask;
|
||||
|
||||
if (arg1 == 0 || arg2 == 0) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
/* Save current context in arg1. */
|
||||
ret = get_errno(sigprocmask(0, NULL, &sigmask));
|
||||
if (!is_error(ret)) {
|
||||
ucp = lock_user(VERIFY_WRITE, arg1, sizeof(target_ucontext_t), 0);
|
||||
if (ucp == 0) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_mcontext(cpu_env, &ucp->uc_mcontext, TARGET_MC_GET_CLEAR_RET);
|
||||
host_to_target_sigset(&ucp->uc_sigmask, &sigmask);
|
||||
memset(ucp->__spare__, 0, sizeof(ucp->__spare__));
|
||||
unlock_user(ucp, arg1, sizeof(target_ucontext_t));
|
||||
}
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Restore the context in arg2 to the current context. */
|
||||
ucp = lock_user(VERIFY_READ, arg2, sizeof(target_ucontext_t), 1);
|
||||
if (ucp == 0) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = set_mcontext(cpu_env, &ucp->uc_mcontext, 0);
|
||||
target_to_host_sigset(&sigmask, &ucp->uc_sigmask);
|
||||
unlock_user(ucp, arg2, sizeof(target_ucontext_t));
|
||||
if (!is_error(ret)) {
|
||||
(void)sigprocmask(SIG_SETMASK, &sigmask, NULL);
|
||||
}
|
||||
return ret == 0 ? -TARGET_EJUSTRETURN : ret;
|
||||
}
|
||||
|
||||
|
||||
/* undocumented _umtx_lock() */
|
||||
static inline abi_long do_freebsd__umtx_lock(abi_ulong target_addr)
|
||||
{
|
||||
abi_long ret;
|
||||
long tid;
|
||||
|
||||
ret = get_errno(thr_self(&tid));
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
return freebsd_lock_umtx(target_addr, tid, 0, NULL);
|
||||
}
|
||||
|
||||
/* undocumented _umtx_unlock() */
|
||||
static inline abi_long do_freebsd__umtx_unlock(abi_ulong target_addr)
|
||||
{
|
||||
abi_long ret;
|
||||
long tid;
|
||||
|
||||
ret = get_errno(thr_self(&tid));
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
return freebsd_unlock_umtx(target_addr, tid);
|
||||
}
|
||||
|
||||
#define safe_g2h_untagged(x) ((x) != 0 ? g2h_untagged(x) : NULL)
|
||||
|
||||
/* undocumented _umtx_op(void *obj, int op, u_long val, void *uaddr,
|
||||
void *target_time); */
|
||||
static inline abi_long do_freebsd__umtx_op(abi_ulong obj, int op, abi_ulong val,
|
||||
abi_ulong uaddr, abi_ulong target_time)
|
||||
{
|
||||
abi_long ret;
|
||||
#ifndef _UMTX_OPTIMIZED
|
||||
struct _umtx_time ut[2];
|
||||
struct timespec ts;
|
||||
size_t utsz;
|
||||
long tid;
|
||||
#endif
|
||||
|
||||
switch (op) {
|
||||
case TARGET_UMTX_OP_LOCK:
|
||||
#ifdef _UMTX_OPTIMIZED
|
||||
if (target_time != 0 && !access_ok(VERIFY_READ, target_time, uaddr))
|
||||
return -TARGET_EFAULT;
|
||||
ret = freebsd_lock_umtx(obj, 0, uaddr, safe_g2h_untagged(target_time));
|
||||
#else
|
||||
ret = get_errno(thr_self(&tid));
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (target_time != 0) {
|
||||
ret = t2h_freebsd_umtx_time(target_time, uaddr, ut, &utsz);
|
||||
if (is_error(ret))
|
||||
return ret;
|
||||
ret = freebsd_lock_umtx(obj, tid, utsz, &ut);
|
||||
} else {
|
||||
ret = freebsd_lock_umtx(obj, tid, 0, NULL);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TARGET_UMTX_OP_UNLOCK:
|
||||
#ifdef _UMTX_OPTIMIZED
|
||||
ret = freebsd_unlock_umtx(obj, 0);
|
||||
#else
|
||||
ret = get_errno(thr_self(&tid));
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
ret = freebsd_unlock_umtx(obj, tid);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TARGET_UMTX_OP_WAIT:
|
||||
/* args: obj *, val, (void *)sizeof(ut), ut * */
|
||||
#ifdef _UMTX_OPTIMIZED
|
||||
if (target_time != 0 && !access_ok(VERIFY_READ, target_time, uaddr))
|
||||
return -TARGET_EFAULT;
|
||||
ret = freebsd_umtx_wait(obj, val, uaddr, safe_g2h_untagged(target_time));
|
||||
#else
|
||||
if (target_time != 0) {
|
||||
ret = t2h_freebsd_umtx_time(target_time, uaddr, ut, &utsz);
|
||||
if (is_error(ret))
|
||||
return ret;
|
||||
ret = freebsd_umtx_wait(obj, tswapal(val), utsz, &ut);
|
||||
} else {
|
||||
ret = freebsd_umtx_wait(obj, tswapal(val), 0, NULL);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TARGET_UMTX_OP_WAKE:
|
||||
/* args: obj *, nr_wakeup */
|
||||
ret = freebsd_umtx_wake(obj, val);
|
||||
break;
|
||||
|
||||
case TARGET_UMTX_OP_MUTEX_LOCK:
|
||||
#ifdef _UMTX_OPTIMIZED
|
||||
if (target_time != 0 && !access_ok(VERIFY_READ, target_time, uaddr))
|
||||
return -TARGET_EFAULT;
|
||||
ret = freebsd_lock_umutex(obj, 0, safe_g2h_untagged(target_time), uaddr, 0, val);
|
||||
#else
|
||||
ret = get_errno(thr_self(&tid));
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
if (target_time != 0) {
|
||||
ret = t2h_freebsd_umtx_time(target_time, uaddr, ut, &utsz);
|
||||
if (is_error(ret))
|
||||
return ret;
|
||||
ret = freebsd_lock_umutex(obj, tid, ut, utsz, 0, tswapal(val));
|
||||
} else {
|
||||
ret = freebsd_lock_umutex(obj, tid, NULL, 0, 0, tswapal(val));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TARGET_UMTX_OP_MUTEX_UNLOCK:
|
||||
#ifdef _UMTX_OPTIMIZED
|
||||
ret = freebsd_unlock_umutex(obj, 0);
|
||||
#else
|
||||
ret = get_errno(thr_self(&tid));
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
ret = freebsd_unlock_umutex(obj, tid);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TARGET_UMTX_OP_MUTEX_TRYLOCK:
|
||||
#ifdef _UMTX_OPTIMIZED
|
||||
ret = freebsd_lock_umutex(obj, 0, NULL, 0, TARGET_UMUTEX_TRY, val);
|
||||
#else
|
||||
ret = get_errno(thr_self(&tid));
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
ret = freebsd_lock_umutex(obj, tid, NULL, 0, TARGET_UMUTEX_TRY,
|
||||
tswapal(val));
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TARGET_UMTX_OP_MUTEX_WAIT:
|
||||
#ifdef _UMTX_OPTIMIZED
|
||||
if (target_time != 0 && !access_ok(VERIFY_READ, target_time, uaddr))
|
||||
return -TARGET_EFAULT;
|
||||
ret = freebsd_lock_umutex(obj, 0, safe_g2h_untagged(target_time), uaddr,
|
||||
TARGET_UMUTEX_WAIT, val);
|
||||
#else
|
||||
ret = get_errno(thr_self(&tid));
|
||||
if (is_error(ret)) {
|
||||
return ret;
|
||||
}
|
||||
if (target_time != 0) {
|
||||
ret = t2h_freebsd_umtx_time(target_time, uaddr, ut, &utsz);
|
||||
if (is_error(ret))
|
||||
return ret;
|
||||
ret = freebsd_lock_umutex(obj, tid, ut, utsz, TARGET_UMUTEX_WAIT,
|
||||
tswapal(val));
|
||||
} else {
|
||||
ret = freebsd_lock_umutex(obj, tid, NULL, 0, TARGET_UMUTEX_WAIT,
|
||||
tswapal(val));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TARGET_UMTX_OP_MUTEX_WAKE:
|
||||
/* Don't need to do access_ok(). */
|
||||
ret = freebsd_umtx_mutex_wake(obj, val);
|
||||
break;
|
||||
|
||||
case TARGET_UMTX_OP_SET_CEILING:
|
||||
ret = 0; /* XXX quietly ignore these things for now */
|
||||
break;
|
||||
|
||||
case TARGET_UMTX_OP_CV_WAIT:
|
||||
#ifdef _UMTX_OPTIMIZED
|
||||
if (target_time != 0 && !access_ok(VERIFY_READ, target_time, uaddr))
|
||||
return -TARGET_EFAULT;
|
||||
ret = freebsd_cv_wait(obj, uaddr, safe_g2h_untagged(target_time), val);
|
||||
#else
|
||||
/*
|
||||
* Initialization of the struct conv is done by
|
||||
* bzero'ing everything in userland.
|
||||
*/
|
||||
if (target_time != 0) {
|
||||
if (t2h_freebsd_timespec(&ts, target_time)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = freebsd_cv_wait(obj, uaddr, &ts, val);
|
||||
} else {
|
||||
ret = freebsd_cv_wait(obj, uaddr, NULL, val);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TARGET_UMTX_OP_CV_SIGNAL:
|
||||
/*
|
||||
* XXX
|
||||
* User code may check if c_has_waiters is zero. Other
|
||||
* than that it is assume that user code doesn't do
|
||||
* much with the struct conv fields and is pretty
|
||||
* much opauque to userland.
|
||||
*/
|
||||
ret = freebsd_cv_signal(obj);
|
||||
break;
|
||||
|
||||
case TARGET_UMTX_OP_CV_BROADCAST:
|
||||
/*
|
||||
* XXX
|
||||
* User code may check if c_has_waiters is zero. Other
|
||||
* than that it is assume that user code doesn't do
|
||||
* much with the struct conv fields and is pretty
|
||||
* much opauque to userland.
|
||||
*/
|
||||
ret = freebsd_cv_broadcast(obj);
|
||||
break;
|
||||
|
||||
case TARGET_UMTX_OP_WAIT_UINT:
|
||||
#ifdef _UMTX_OPTIMIZED
|
||||
if (target_time != 0 && !access_ok(VERIFY_READ, target_time, uaddr))
|
||||
return -TARGET_EFAULT;
|
||||
ret = freebsd_umtx_wait_uint(obj, val, uaddr, safe_g2h_untagged(target_time));
|
||||
#else
|
||||
if (!access_ok(VERIFY_READ, obj, sizeof(abi_ulong))) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
/* args: obj *, val, (void *)sizeof(ut), ut * */
|
||||
if (target_time != 0) {
|
||||
ret = t2h_freebsd_umtx_time(target_time, uaddr, ut, &utsz);
|
||||
if (is_error(ret))
|
||||
return ret;
|
||||
ret = freebsd_umtx_wait_uint(obj, tswap32((uint32_t)val),
|
||||
utsz, &ut);
|
||||
} else {
|
||||
ret = freebsd_umtx_wait_uint(obj, tswap32((uint32_t)val), 0, NULL);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TARGET_UMTX_OP_WAIT_UINT_PRIVATE:
|
||||
#ifdef _UMTX_OPTIMIZED
|
||||
if (target_time != 0 && !access_ok(VERIFY_READ, target_time, uaddr))
|
||||
return -TARGET_EFAULT;
|
||||
ret = freebsd_umtx_wait_uint_private(obj, val, uaddr,
|
||||
safe_g2h_untagged(target_time));
|
||||
#else
|
||||
if (!access_ok(VERIFY_READ, obj, sizeof(abi_ulong))) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
/* args: obj *, val, (void *)sizeof(ut), ut * */
|
||||
if (target_time != 0) {
|
||||
ret = t2h_freebsd_umtx_time(target_time, uaddr, ut, &utsz);
|
||||
if (is_error(ret))
|
||||
return ret;
|
||||
ret = freebsd_umtx_wait_uint_private(obj, tswap32((uint32_t)val),
|
||||
utsz, &ut);
|
||||
} else {
|
||||
ret = freebsd_umtx_wait_uint_private(obj, tswap32((uint32_t)val),
|
||||
0, NULL);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TARGET_UMTX_OP_WAKE_PRIVATE:
|
||||
/* Don't need to do access_ok(). */
|
||||
ret = freebsd_umtx_wake_private(obj, val);
|
||||
break;
|
||||
|
||||
case TARGET_UMTX_OP_RW_RDLOCK:
|
||||
#ifdef _UMTX_OPTIMIZED
|
||||
if (target_time != 0 && !access_ok(VERIFY_READ, target_time, uaddr))
|
||||
return -TARGET_EFAULT;
|
||||
ret = freebsd_rw_rdlock(obj, val, uaddr, safe_g2h_untagged(target_time));
|
||||
#else
|
||||
if (target_time != 0) {
|
||||
ret = t2h_freebsd_umtx_time(target_time, uaddr, ut, &utsz);
|
||||
if (is_error(ret))
|
||||
return ret;
|
||||
ret = freebsd_rw_rdlock(obj, val, utsz, &ut);
|
||||
} else {
|
||||
ret = freebsd_rw_rdlock(obj, val, 0, NULL);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TARGET_UMTX_OP_RW_WRLOCK:
|
||||
#ifdef _UMTX_OPTIMIZED
|
||||
if (target_time != 0 && !access_ok(VERIFY_READ, target_time, uaddr))
|
||||
return -TARGET_EFAULT;
|
||||
ret = freebsd_rw_wrlock(obj, val, uaddr, safe_g2h_untagged(target_time));
|
||||
#else
|
||||
if (target_time != 0) {
|
||||
ret = t2h_freebsd_umtx_time(target_time, uaddr, ut, &utsz);
|
||||
if (is_error(ret))
|
||||
return ret;
|
||||
ret = freebsd_rw_wrlock(obj, val, utsz, &ut);
|
||||
} else {
|
||||
ret = freebsd_rw_wrlock(obj, val, 0, NULL);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TARGET_UMTX_OP_RW_UNLOCK:
|
||||
ret = freebsd_rw_unlock(obj);
|
||||
break;
|
||||
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version > 900000
|
||||
#ifdef UMTX_OP_MUTEX_WAKE2
|
||||
case TARGET_UMTX_OP_MUTEX_WAKE2:
|
||||
ret = freebsd_umtx_mutex_wake2(obj, val);
|
||||
break;
|
||||
#endif /* UMTX_OP_MUTEX_WAKE2 */
|
||||
|
||||
#ifdef UMTX_OP_NWAKE_PRIVATE
|
||||
case TARGET_UMTX_OP_NWAKE_PRIVATE:
|
||||
ret = freebsd_umtx_nwake_private(obj, val);
|
||||
break;
|
||||
#endif /* UMTX_OP_NWAKE_PRIVATE */
|
||||
|
||||
#if __FreeBSD_version > 1100000
|
||||
case TARGET_UMTX_OP_SEM2_WAIT:
|
||||
/* args: obj *, val, (void *)sizeof(ut), ut * */
|
||||
#ifdef _UMTX_OPTIMIZED
|
||||
if (target_time != 0 && !access_ok(
|
||||
(uaddr > sizeof(struct target_freebsd__umtx_time) ? VERIFY_WRITE :
|
||||
VERIFY_READ), target_time, uaddr))
|
||||
return -TARGET_EFAULT;
|
||||
ret = freebsd_umtx_sem2_wait(obj, uaddr, safe_g2h_untagged(target_time));
|
||||
#else
|
||||
if (target_time != 0) {
|
||||
ret = t2h_freebsd_umtx_time(target_time, uaddr, ut, &utsz);
|
||||
if (is_error(ret))
|
||||
return ret;
|
||||
/* Kernel writes out the ut[1] if utsz >= _umtx_time + timespec. */
|
||||
ret = freebsd_umtx_sem2_wait(obj, utsz, ut);
|
||||
if (ret == -TARGET_EINTR && (ut[0]._flags & UMTX_ABSTIME) == 0 &&
|
||||
utsz >= sizeof(struct target_freebsd__umtx_time) +
|
||||
sizeof(struct target_freebsd_timespec)) {
|
||||
abi_ulong cret;
|
||||
|
||||
cret = h2t_freebsd_timespec(target_time +
|
||||
sizeof(struct target_freebsd__umtx_time), &ut[1]._timeout);
|
||||
if (is_error(cret))
|
||||
ret = cret;
|
||||
}
|
||||
} else {
|
||||
ret = freebsd_umtx_sem2_wait(obj, 0, NULL);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TARGET_UMTX_OP_SEM2_WAKE:
|
||||
/* Don't need to do access_ok(). */
|
||||
ret = freebsd_umtx_sem2_wake(obj);
|
||||
break;
|
||||
#endif /* __FreeBSD_version > 1100000 */
|
||||
case TARGET_UMTX_OP_SEM_WAIT:
|
||||
/* args: obj *, val, (void *)sizeof(ut), ut * */
|
||||
#ifdef _UMTX_OPTIMIZED
|
||||
if (target_time != 0 && !access_ok(VERIFY_READ, target_time, uaddr))
|
||||
return -TARGET_EFAULT;
|
||||
ret = freebsd_umtx_sem_wait(obj, uaddr, safe_g2h_untagged(target_time));
|
||||
#else
|
||||
if (target_time != 0) {
|
||||
ret = t2h_freebsd_umtx_time(target_time, uaddr, ut, &utsz);
|
||||
if (is_error(ret))
|
||||
return ret;
|
||||
ret = freebsd_umtx_sem_wait(obj, utsz, ut);
|
||||
} else {
|
||||
ret = freebsd_umtx_sem_wait(obj, 0, NULL);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TARGET_UMTX_OP_SEM_WAKE:
|
||||
/* Don't need to do access_ok(). */
|
||||
ret = freebsd_umtx_sem_wake(obj);
|
||||
break;
|
||||
#if __FreeBSD_version > 1200000
|
||||
case UMTX_OP_SHM:
|
||||
ret = freebsd_umtx_shm(uaddr, val);
|
||||
break;
|
||||
case TARGET_UMTX_OP_ROBUST_LISTS:
|
||||
ret = freebsd_umtx_robust_list(uaddr, val);
|
||||
break;
|
||||
#endif /* __FreeBSD_version > 1200000 */
|
||||
|
||||
#endif
|
||||
default:
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* !__FREEBSD_OS_THREAD_H_ */
|
|
@ -0,0 +1,322 @@
|
|||
/*
|
||||
* FreeBSD time related system call helpers
|
||||
*
|
||||
* Copyright (c) 2013-15 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/>.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <sys/timex.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/umtx.h>
|
||||
|
||||
#include "qemu.h"
|
||||
#include "qemu-os.h"
|
||||
|
||||
/*
|
||||
* FreeBSD time conversion functions
|
||||
*/
|
||||
abi_long t2h_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr)
|
||||
{
|
||||
struct target_freebsd_timeval *target_tv;
|
||||
|
||||
if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__get_user(tv->tv_sec, &target_tv->tv_sec);
|
||||
__get_user(tv->tv_usec, &target_tv->tv_usec);
|
||||
unlock_user_struct(target_tv, target_tv_addr, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long h2t_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr)
|
||||
{
|
||||
struct target_freebsd_timeval *target_tv;
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__put_user(tv->tv_sec, &target_tv->tv_sec);
|
||||
__put_user(tv->tv_usec, &target_tv->tv_usec);
|
||||
unlock_user_struct(target_tv, target_tv_addr, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long t2h_freebsd_timespec(struct timespec *ts, abi_ulong target_ts_addr)
|
||||
{
|
||||
struct target_freebsd_timespec *target_ts;
|
||||
|
||||
if (!lock_user_struct(VERIFY_READ, target_ts, target_ts_addr, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__get_user(ts->tv_sec, &target_ts->tv_sec);
|
||||
__get_user(ts->tv_nsec, &target_ts->tv_nsec);
|
||||
unlock_user_struct(target_ts, target_ts_addr, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long h2t_freebsd_timespec(abi_ulong target_ts_addr, struct timespec *ts)
|
||||
{
|
||||
struct target_freebsd_timespec *target_ts;
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_ts, target_ts_addr, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__put_user(ts->tv_sec, &target_ts->tv_sec);
|
||||
__put_user(ts->tv_nsec, &target_ts->tv_nsec);
|
||||
unlock_user_struct(target_ts, target_ts_addr, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long t2h_freebsd_umtx_time(abi_ulong target_ut_addr,
|
||||
abi_ulong target_ut_size, void *host_t, size_t *host_tsz)
|
||||
{
|
||||
abi_long ret;
|
||||
|
||||
if (target_ut_size <= sizeof(struct target_freebsd_timespec)) {
|
||||
ret = t2h_freebsd_timespec((struct timespec *)host_t, target_ut_addr);
|
||||
if (ret == 0)
|
||||
*host_tsz = sizeof(struct timespec);
|
||||
return ret;
|
||||
} else {
|
||||
struct target_freebsd__umtx_time *target_ut;
|
||||
struct _umtx_time *ut = (struct _umtx_time *)host_t;
|
||||
|
||||
if (!lock_user_struct(VERIFY_READ, target_ut, target_ut_addr, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if (t2h_freebsd_timespec(&ut->_timeout, h2g(&target_ut->_timeout))) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__get_user(ut->_flags, &target_ut->_flags);
|
||||
__get_user(ut->_clockid, &target_ut->_clockid);
|
||||
unlock_user_struct(target_ut, target_ut_addr, 1);
|
||||
|
||||
if (target_ut_size > sizeof(struct target_freebsd__umtx_time))
|
||||
*host_tsz = sizeof(struct _umtx_time) + sizeof(struct timespec);
|
||||
else
|
||||
*host_tsz = sizeof(struct _umtx_time);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
abi_long t2h_freebsd_timex(struct timex *host_tx, abi_ulong target_tx_addr)
|
||||
{
|
||||
struct target_freebsd_timex *target_tx;
|
||||
|
||||
if (!lock_user_struct(VERIFY_READ, target_tx, target_tx_addr, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__get_user(host_tx->modes, &target_tx->modes);
|
||||
__get_user(host_tx->offset, &target_tx->offset);
|
||||
__get_user(host_tx->freq, &target_tx->freq);
|
||||
__get_user(host_tx->maxerror, &target_tx->maxerror);
|
||||
__get_user(host_tx->esterror, &target_tx->esterror);
|
||||
__get_user(host_tx->status, &target_tx->status);
|
||||
__get_user(host_tx->constant, &target_tx->constant);
|
||||
__get_user(host_tx->precision, &target_tx->precision);
|
||||
__get_user(host_tx->ppsfreq, &target_tx->ppsfreq);
|
||||
__get_user(host_tx->jitter, &target_tx->jitter);
|
||||
__get_user(host_tx->shift, &target_tx->shift);
|
||||
__get_user(host_tx->stabil, &target_tx->stabil);
|
||||
__get_user(host_tx->jitcnt, &target_tx->jitcnt);
|
||||
__get_user(host_tx->calcnt, &target_tx->calcnt);
|
||||
__get_user(host_tx->errcnt, &target_tx->errcnt);
|
||||
__get_user(host_tx->stbcnt, &target_tx->stbcnt);
|
||||
unlock_user_struct(target_tx, target_tx_addr, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long h2t_freebsd_ntptimeval(abi_ulong target_ntv_addr,
|
||||
struct ntptimeval *ntv)
|
||||
{
|
||||
struct target_freebsd_ntptimeval *target_ntv;
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_ntv, target_ntv_addr, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__put_user(ntv->time.tv_sec, &target_ntv->time.tv_sec);
|
||||
__put_user(ntv->time.tv_nsec, &target_ntv->time.tv_nsec);
|
||||
__put_user(ntv->maxerror, &target_ntv->maxerror);
|
||||
__put_user(ntv->esterror, &target_ntv->esterror);
|
||||
__put_user(ntv->tai, &target_ntv->tai);
|
||||
__put_user(ntv->time_state, &target_ntv->time_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* select(2) fdset copy functions
|
||||
*/
|
||||
abi_ulong copy_from_user_fdset(fd_set *fds, abi_ulong target_fds_addr, int n)
|
||||
{
|
||||
int i, nw, j, k;
|
||||
abi_ulong b, *target_fds;
|
||||
|
||||
nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
|
||||
target_fds = lock_user(VERIFY_READ, target_fds_addr,
|
||||
sizeof(abi_ulong) * nw, 1);
|
||||
if (target_fds == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
FD_ZERO(fds);
|
||||
k = 0;
|
||||
for (i = 0; i < nw; i++) {
|
||||
/* grab the abi_ulong */
|
||||
__get_user(b, &target_fds[i]);
|
||||
for (j = 0; j < TARGET_ABI_BITS; j++) {
|
||||
/* check the bit inside the abi_ulong */
|
||||
if ((b >> j) & 1) {
|
||||
FD_SET(k, fds);
|
||||
}
|
||||
k++;
|
||||
}
|
||||
}
|
||||
unlock_user(target_fds, target_fds_addr, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
|
||||
abi_ulong target_fds_addr, int n)
|
||||
{
|
||||
|
||||
if (target_fds_addr) {
|
||||
if (copy_from_user_fdset(fds, target_fds_addr, n)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
*fds_ptr = fds;
|
||||
} else {
|
||||
*fds_ptr = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long copy_to_user_fdset(abi_ulong target_fds_addr, const fd_set *fds, int n)
|
||||
{
|
||||
int i, nw, j, k;
|
||||
abi_long v;
|
||||
abi_ulong *target_fds;
|
||||
|
||||
nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
|
||||
target_fds = lock_user(VERIFY_WRITE, target_fds_addr,
|
||||
sizeof(abi_ulong) * nw, 0);
|
||||
if (target_fds == NULL) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
k = 0;
|
||||
for (i = 0; i < nw; i++) {
|
||||
v = 0;
|
||||
for (j = 0; j < TARGET_ABI_BITS; j++) {
|
||||
v |= ((FD_ISSET(k, fds) != 0) << j);
|
||||
k++;
|
||||
}
|
||||
__put_user(v, &target_fds[i]);
|
||||
}
|
||||
unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_int next_free_host_timer(void)
|
||||
{
|
||||
int k ;
|
||||
/* FIXME: Does finding the next free slot require a lock? */
|
||||
for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
|
||||
if (g_posix_timers[k] == 0) {
|
||||
g_posix_timers[k] = 1;
|
||||
return k;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int host_to_target_timerid(int timerid)
|
||||
{
|
||||
int k;
|
||||
|
||||
for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
|
||||
if (g_posix_timers[k] == timerid)
|
||||
return TIMER_MAGIC | k;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
|
||||
abi_ulong target_addr)
|
||||
{
|
||||
struct target_freebsd_itimerspec *target_itspec;
|
||||
|
||||
if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
|
||||
host_itspec->it_interval.tv_sec =
|
||||
tswapal(target_itspec->it_interval.tv_sec);
|
||||
host_itspec->it_interval.tv_nsec =
|
||||
tswapal(target_itspec->it_interval.tv_nsec);
|
||||
host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
|
||||
host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
|
||||
|
||||
unlock_user_struct(target_itspec, target_addr, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long host_to_target_itimerspec(abi_ulong target_addr,
|
||||
struct itimerspec *host_its)
|
||||
{
|
||||
struct target_freebsd_itimerspec *target_itspec;
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
|
||||
target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
|
||||
target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
|
||||
|
||||
target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
|
||||
target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
|
||||
|
||||
unlock_user_struct(target_itspec, target_addr, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert QEMU provided timer ID back to internal 16bit index format */
|
||||
int get_timer_id(abi_long arg)
|
||||
{
|
||||
int timerid = arg;
|
||||
|
||||
if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
|
||||
timerid &= 0xffff;
|
||||
|
||||
if (timerid >= ARRAY_SIZE(g_posix_timers)) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
|
||||
return timerid;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* FreeBSD conversion extern declarations
|
||||
*
|
||||
* 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 _QEMU_OS_H_
|
||||
#define _QEMU_OS_H_
|
||||
|
||||
#define _WANT_FREEBSD11_STAT
|
||||
#define _WANT_FREEBSD11_STATFS
|
||||
#define _WANT_FREEBSD11_DIRENT
|
||||
#include <sys/types.h>
|
||||
#include <sys/acl.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/timex.h>
|
||||
#include <sys/rtprio.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#ifndef BSD_HAVE_INO64
|
||||
#define freebsd11_stat stat
|
||||
#define freebsd11_statfs statfs
|
||||
#endif
|
||||
|
||||
struct freebsd11_stat;
|
||||
|
||||
/* os-time.c */
|
||||
abi_long t2h_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr);
|
||||
abi_long h2t_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr);
|
||||
|
||||
abi_long t2h_freebsd_timespec(struct timespec *ts, abi_ulong target_ts_addr);
|
||||
abi_long h2t_freebsd_timespec(abi_ulong target_ts_addr, struct timespec *ts);
|
||||
|
||||
abi_long t2h_freebsd_umtx_time(abi_ulong target_ut_addr,
|
||||
abi_ulong target_ut_size, void *host_t, size_t *host_tsz);
|
||||
|
||||
abi_long t2h_freebsd_timex(struct timex *host_tx, abi_ulong target_tx_addr);
|
||||
|
||||
abi_long h2t_freebsd_ntptimeval(abi_ulong target_ntv_addr,
|
||||
struct ntptimeval *ntv);
|
||||
|
||||
abi_ulong copy_from_user_fdset(fd_set *fds, abi_ulong target_fds_addr, int n);
|
||||
abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
|
||||
abi_ulong target_fds_addr, int n);
|
||||
abi_long copy_to_user_fdset(abi_ulong target_fds_addr, const fd_set *fds,
|
||||
int n);
|
||||
|
||||
abi_int next_free_host_timer(void);
|
||||
int host_to_target_timerid(int timerid);
|
||||
abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
|
||||
abi_ulong target_addr);
|
||||
abi_long host_to_target_itimerspec(abi_ulong target_addr,
|
||||
struct itimerspec *host_its);
|
||||
int get_timer_id(abi_long arg);
|
||||
|
||||
/* os-socket.c */
|
||||
abi_long t2h_freebsd_cmsg(struct msghdr *msgh,
|
||||
struct target_msghdr *target_msgh);
|
||||
abi_long h2t_freebsd_cmsg(struct target_msghdr *target_msgh,
|
||||
struct msghdr *msgh);
|
||||
|
||||
/* os-stat.c */
|
||||
abi_long h2t_freebsd11_stat(abi_ulong target_addr,
|
||||
struct freebsd11_stat *host_st);
|
||||
abi_long h2t_freebsd11_nstat(abi_ulong target_addr,
|
||||
struct freebsd11_stat *host_st);
|
||||
abi_long t2h_freebsd_fhandle(fhandle_t *host_fh, abi_ulong target_addr);
|
||||
abi_long h2t_freebsd_fhandle(abi_ulong target_addr, fhandle_t *host_fh);
|
||||
abi_long h2t_freebsd11_statfs(abi_ulong target_addr,
|
||||
struct freebsd11_statfs *host_statfs);
|
||||
abi_long target_to_host_fcntl_cmd(int cmd);
|
||||
#ifdef BSD_HAVE_INO64
|
||||
abi_long h2t_freebsd_stat(abi_ulong target_addr,
|
||||
struct stat *host_st);
|
||||
abi_long h2t_freebsd_statfs(abi_ulong target_addr,
|
||||
struct statfs *host_statfs);
|
||||
#endif
|
||||
|
||||
/* os-thread.c */
|
||||
abi_long t2h_freebsd_rtprio(struct rtprio *host_rtp, abi_ulong target_addr);
|
||||
abi_long h2t_freebsd_rtprio(abi_ulong target_addr, struct rtprio *host_rtp);
|
||||
abi_long do_freebsd_thr_new(CPUArchState *env, abi_ulong target_param_addr,
|
||||
int32_t param_size);
|
||||
|
||||
/* os-extattr.c */
|
||||
struct acl;
|
||||
abi_long t2h_freebsd_acl(struct acl *host_acl, abi_ulong target_addr);
|
||||
abi_long h2t_freebsd_acl(abi_ulong target_addr, struct acl *host_acl);
|
||||
abi_long t2h_freebsd_acl_type(acl_type_t *host_type, abi_long target_type);
|
||||
|
||||
#endif /* !_QEMU_OS_H_ */
|
|
@ -163,7 +163,7 @@
|
|||
{ TARGET_FREEBSD_NR_msgget, "msgget", NULL, NULL, NULL },
|
||||
{ TARGET_FREEBSD_NR_msgrcv, "msgrcv", NULL, NULL, NULL },
|
||||
{ TARGET_FREEBSD_NR_msgsnd, "msgsnd", NULL, NULL, NULL },
|
||||
{ TARGET_FREEBSD_NR_msync, "msync", NULL, NULL, NULL },
|
||||
{ TARGET_FREEBSD_NR_msync, "msync", "%s(%p,%d,%d)", NULL, NULL },
|
||||
{ TARGET_FREEBSD_NR_munlock, "munlock", NULL, NULL, NULL },
|
||||
{ TARGET_FREEBSD_NR_munlockall, "munlockall", NULL, NULL, NULL },
|
||||
{ TARGET_FREEBSD_NR_munmap, "munmap", "%s(%p,%d)", NULL, NULL },
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -22,7 +22,7 @@
|
|||
#include "target_arch_elf.h"
|
||||
#include "elf.h"
|
||||
|
||||
#define bsd_get_ncpu() 1 /* until we pull in bsd-proc.[hc] */
|
||||
#include "bsd-proc.h"
|
||||
|
||||
/* this flag is uneffective under linux too, should be deleted */
|
||||
#ifndef MAP_DENYWRITE
|
||||
|
@ -116,10 +116,12 @@ static abi_ulong target_create_elf_tables(abi_ulong p, int argc, int envc,
|
|||
features = ELF_HWCAP2;
|
||||
NEW_AUX_ENT(FREEBSD_AT_HWCAP2, features);
|
||||
#endif
|
||||
#ifndef TARGET_PPC
|
||||
NEW_AUX_ENT(AT_UID, (abi_ulong)getuid());
|
||||
NEW_AUX_ENT(AT_EUID, (abi_ulong)geteuid());
|
||||
NEW_AUX_ENT(AT_GID, (abi_ulong)getgid());
|
||||
NEW_AUX_ENT(AT_EGID, (abi_ulong)getegid());
|
||||
#endif
|
||||
target_auxents = sp; /* Note where the aux entries are in the target */
|
||||
#ifdef ARCH_DLINFO
|
||||
/*
|
||||
|
|
|
@ -61,7 +61,7 @@ static inline int setup_initial_stack(struct bsd_binprm *bprm,
|
|||
|
||||
/* Add machine depedent sigcode. */
|
||||
p -= TARGET_SZSIGCODE;
|
||||
if (setup_sigtramp(p, (unsigned)offsetof(struct target_sigframe, sf_uc),
|
||||
if (TARGET_SZSIGCODE > 0 && setup_sigtramp(p, (unsigned)offsetof(struct target_sigframe, sf_uc),
|
||||
TARGET_FREEBSD_NR_sigreturn)) {
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
|
@ -75,7 +75,8 @@ static inline int setup_initial_stack(struct bsd_binprm *bprm,
|
|||
}
|
||||
}
|
||||
/* Add canary for SSP. */
|
||||
qemu_guest_getrandom_nofail(canary, sizeof(canary));
|
||||
// qemu_guest_getrandom_nofail(canary, sizeof(canary));
|
||||
arc4random_buf(canary, sizeof(canary));
|
||||
p -= roundup(sizeof(canary), sizeof(abi_ulong));
|
||||
if (memcpy_to_target(p, canary, sizeof(canary))) {
|
||||
errno = EFAULT;
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* hostdep.h : things which are dependent on the host architecture
|
||||
*
|
||||
* * Written by Peter Maydell <peter.maydell@linaro.org>
|
||||
*
|
||||
* Copyright (C) 2016 Linaro Limited
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef AARCH64_HOSTDEP_H
|
||||
#define AARCH64_HOSTDEP_H
|
||||
|
||||
/* We have a safe-syscall.inc.S */
|
||||
#define HAVE_SAFE_SYSCALL
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
/* These are defined by the safe-syscall.inc.S file */
|
||||
extern char safe_syscall_start[];
|
||||
extern char safe_syscall_end[];
|
||||
|
||||
/* FreeBSD-ism */
|
||||
#define DEFINE_PCREG(puc) &((ucontext_t *)(puc))->uc_mcontext.mc_gpregs.gp_lr
|
||||
|
||||
/* Adjust the signal context to rewind out of safe-syscall if we're in it */
|
||||
static inline void rewind_if_in_safe_syscall(void *puc)
|
||||
{
|
||||
__u64 *pcreg = DEFINE_PCREG(puc);
|
||||
|
||||
if (*pcreg > (uintptr_t)safe_syscall_start
|
||||
&& *pcreg < (uintptr_t)safe_syscall_end) {
|
||||
*pcreg = (uintptr_t)safe_syscall_start;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
#endif
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* safe-syscall.inc.S : host-specific assembly fragment
|
||||
* to handle signals occurring at the same time as system calls.
|
||||
* This is intended to be included by linux-user/safe-syscall.S
|
||||
*
|
||||
* Written by Richard Henderson <rth@twiddle.net>
|
||||
* Copyright (C) 2016 Red Hat, Inc.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
.global safe_syscall_base
|
||||
.global safe_syscall_start
|
||||
.global safe_syscall_end
|
||||
.type safe_syscall_base, #function
|
||||
.type safe_syscall_start, #function
|
||||
.type safe_syscall_end, #function
|
||||
|
||||
/* This is the entry point for making a system call. The calling
|
||||
* convention here is that of a C varargs function with the
|
||||
* first argument an 'int *' to the signal_pending flag, the
|
||||
* second one the system call number (as a 'long'), and all further
|
||||
* arguments being syscall arguments (also 'long').
|
||||
* We return a long which is the syscall's return value, which
|
||||
* may be negative-errno on failure. Conversion to the
|
||||
* -1-and-errno-set convention is done by the calling wrapper.
|
||||
*/
|
||||
safe_syscall_base:
|
||||
.cfi_startproc
|
||||
/* The syscall calling convention isn't the same as the
|
||||
* C one:
|
||||
* we enter with x0 == *signal_pending
|
||||
* x1 == syscall number
|
||||
* x2 ... x7, (stack) == syscall arguments
|
||||
* and return the result in x0
|
||||
* and the syscall instruction needs
|
||||
* x8 == syscall number
|
||||
* x0 ... x6 == syscall arguments
|
||||
* and returns the result in x0
|
||||
* Shuffle everything around appropriately.
|
||||
*/
|
||||
mov x9, x0 /* signal_pending pointer */
|
||||
mov x8, x1 /* syscall number */
|
||||
mov x0, x2 /* syscall arguments */
|
||||
mov x1, x3
|
||||
mov x2, x4
|
||||
mov x3, x5
|
||||
mov x4, x6
|
||||
mov x5, x7
|
||||
ldr x6, [sp]
|
||||
|
||||
/* This next sequence of code works in conjunction with the
|
||||
* rewind_if_safe_syscall_function(). If a signal is taken
|
||||
* and the interrupted PC is anywhere between 'safe_syscall_start'
|
||||
* and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
|
||||
* The code sequence must therefore be able to cope with this, and
|
||||
* the syscall instruction must be the final one in the sequence.
|
||||
*/
|
||||
safe_syscall_start:
|
||||
/* if signal_pending is non-zero, don't do the call */
|
||||
ldr w10, [x9]
|
||||
cbnz w10, 0f
|
||||
svc 0x0
|
||||
safe_syscall_end:
|
||||
/* code path for having successfully executed the syscall */
|
||||
/* Start FreeBSD */
|
||||
b.cc 2f
|
||||
neg x0, x0
|
||||
2f:
|
||||
/* End FreeBSD */
|
||||
ret
|
||||
|
||||
0:
|
||||
/* code path when we didn't execute the syscall */
|
||||
mov x0, #-TARGET_ERESTARTSYS
|
||||
ret
|
||||
.cfi_endproc
|
||||
|
||||
.size safe_syscall_base, .-safe_syscall_base
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* hostdep.h : things which are dependent on the host architecture
|
||||
*
|
||||
* * Written by Peter Maydell <peter.maydell@linaro.org>
|
||||
*
|
||||
* Copyright (C) 2016 Linaro Limited
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef ARM_HOSTDEP_H
|
||||
#define ARM_HOSTDEP_H
|
||||
|
||||
/* We have a safe-syscall.inc.S */
|
||||
#define HAVE_SAFE_SYSCALL
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
/* These are defined by the safe-syscall.inc.S file */
|
||||
extern char safe_syscall_start[];
|
||||
extern char safe_syscall_end[];
|
||||
|
||||
/* FreeBSD-ism */
|
||||
#define DEFINE_PCREG(puc) &((ucontext_t *)(puc))->uc_mcontext.__gregs[_REG_PC]
|
||||
|
||||
/* Adjust the signal context to rewind out of safe-syscall if we're in it */
|
||||
static inline void rewind_if_in_safe_syscall(void *puc)
|
||||
{
|
||||
unsigned long *pcreg = DEFINE_PCREG(puc);
|
||||
|
||||
if (*pcreg > (uintptr_t)safe_syscall_start
|
||||
&& *pcreg < (uintptr_t)safe_syscall_end) {
|
||||
*pcreg = (uintptr_t)safe_syscall_start;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
#endif
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* safe-syscall.inc.S : host-specific assembly fragment
|
||||
* to handle signals occurring at the same time as system calls.
|
||||
* This is intended to be included by linux-user/safe-syscall.S
|
||||
*
|
||||
* Written by Richard Henderson <rth@twiddle.net>
|
||||
* Copyright (C) 2016 Red Hat, Inc.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
.global safe_syscall_base
|
||||
.global safe_syscall_start
|
||||
.global safe_syscall_end
|
||||
.type safe_syscall_base, %function
|
||||
|
||||
.cfi_sections .debug_frame
|
||||
|
||||
.text
|
||||
.syntax unified
|
||||
.arm
|
||||
.align 2
|
||||
|
||||
/* This is the entry point for making a system call. The calling
|
||||
* convention here is that of a C varargs function with the
|
||||
* first argument an 'int *' to the signal_pending flag, the
|
||||
* second one the system call number (as a 'long'), and all further
|
||||
* arguments being syscall arguments (also 'long').
|
||||
* We return a long which is the syscall's return value, which
|
||||
* may be negative-errno on failure. Conversion to the
|
||||
* -1-and-errno-set convention is done by the calling wrapper.
|
||||
*/
|
||||
safe_syscall_base:
|
||||
.fnstart
|
||||
.cfi_startproc
|
||||
mov r12, sp /* save entry stack */
|
||||
push { r4, r5, r6, r7, r8, lr }
|
||||
.save { r4, r5, r6, r7, r8, lr }
|
||||
.cfi_adjust_cfa_offset 24
|
||||
.cfi_rel_offset r4, 0
|
||||
.cfi_rel_offset r5, 4
|
||||
.cfi_rel_offset r6, 8
|
||||
.cfi_rel_offset r7, 12
|
||||
.cfi_rel_offset r8, 16
|
||||
.cfi_rel_offset lr, 20
|
||||
|
||||
/* The syscall calling convention isn't the same as the C one:
|
||||
* we enter with r0 == *signal_pending
|
||||
* r1 == syscall number
|
||||
* r2, r3, [sp+0] ... [sp+12] == syscall arguments
|
||||
* and return the result in r0
|
||||
* and the syscall instruction needs
|
||||
* r7 == syscall number
|
||||
* r0 ... r6 == syscall arguments
|
||||
* and returns the result in r0
|
||||
* Shuffle everything around appropriately.
|
||||
* Note the 16 bytes that we pushed to save registers.
|
||||
*/
|
||||
mov r8, r0 /* copy signal_pending */
|
||||
mov r7, r1 /* syscall number */
|
||||
mov r0, r2 /* syscall args */
|
||||
mov r1, r3
|
||||
ldm r12, { r2, r3, r4, r5, r6 }
|
||||
|
||||
/* This next sequence of code works in conjunction with the
|
||||
* rewind_if_safe_syscall_function(). If a signal is taken
|
||||
* and the interrupted PC is anywhere between 'safe_syscall_start'
|
||||
* and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
|
||||
* The code sequence must therefore be able to cope with this, and
|
||||
* the syscall instruction must be the final one in the sequence.
|
||||
*/
|
||||
safe_syscall_start:
|
||||
/* if signal_pending is non-zero, don't do the call */
|
||||
ldr r12, [r8] /* signal_pending */
|
||||
tst r12, r12
|
||||
bne 1f
|
||||
swi 0
|
||||
safe_syscall_end:
|
||||
/* code path for having successfully executed the syscall */
|
||||
/* Begin FreeBSD */
|
||||
bcc 2f
|
||||
neg r0, r0
|
||||
2:
|
||||
/* End FreeBSD */
|
||||
pop { r4, r5, r6, r7, r8, pc }
|
||||
|
||||
1:
|
||||
/* code path when we didn't execute the syscall */
|
||||
ldr r0, =-TARGET_ERESTARTSYS
|
||||
pop { r4, r5, r6, r7, r8, pc }
|
||||
.fnend
|
||||
.cfi_endproc
|
||||
|
||||
.size safe_syscall_base, .-safe_syscall_base
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* hostdep.h : things which are dependent on the host architecture
|
||||
*
|
||||
* * Written by Peter Maydell <peter.maydell@linaro.org>
|
||||
*
|
||||
* Copyright (C) 2016 Linaro Limited
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef I386_HOSTDEP_H
|
||||
#define I386_HOSTDEP_H
|
||||
|
||||
/* We have a safe-syscall.inc.S */
|
||||
#define HAVE_SAFE_SYSCALL
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
/* These are defined by the safe-syscall.inc.S file */
|
||||
extern char safe_syscall_start[];
|
||||
extern char safe_syscall_end[];
|
||||
|
||||
/* FreeBSD-isms */
|
||||
typedef __register_t greg_t;
|
||||
#define DEFINE_PCREG(puc) &((ucontext_t *)(puc))->uc_mcontext.mc_eip
|
||||
|
||||
/* Adjust the signal context to rewind out of safe-syscall if we're in it */
|
||||
static inline void rewind_if_in_safe_syscall(void *puc)
|
||||
{
|
||||
greg_t *pcreg = DEFINE_PCREG(puc);
|
||||
|
||||
if (*pcreg > (uintptr_t)safe_syscall_start
|
||||
&& *pcreg < (uintptr_t)safe_syscall_end) {
|
||||
*pcreg = (uintptr_t)safe_syscall_start;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
#endif
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* safe-syscall.inc.S : host-specific assembly fragment
|
||||
* to handle signals occurring at the same time as system calls.
|
||||
* This is intended to be included by linux-user/safe-syscall.S
|
||||
*
|
||||
* Written by Richard Henderson <rth@twiddle.net>
|
||||
* Copyright (C) 2016 Red Hat, Inc.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
.global safe_syscall_base
|
||||
.global safe_syscall_start
|
||||
.global safe_syscall_end
|
||||
.type safe_syscall_base, @function
|
||||
|
||||
/* This is the entry point for making a system call. The calling
|
||||
* convention here is that of a C varargs function with the
|
||||
* first argument an 'int *' to the signal_pending flag, the
|
||||
* second one the system call number (as a 'long'), and all further
|
||||
* arguments being syscall arguments (also 'long').
|
||||
* We return a long which is the syscall's return value, which
|
||||
* may be negative-errno on failure. Conversion to the
|
||||
* -1-and-errno-set convention is done by the calling wrapper.
|
||||
*/
|
||||
safe_syscall_base:
|
||||
.cfi_startproc
|
||||
push %ebp
|
||||
.cfi_adjust_cfa_offset 4
|
||||
.cfi_rel_offset ebp, 0
|
||||
push %esi
|
||||
.cfi_adjust_cfa_offset 4
|
||||
.cfi_rel_offset esi, 0
|
||||
push %edi
|
||||
.cfi_adjust_cfa_offset 4
|
||||
.cfi_rel_offset edi, 0
|
||||
push %ebx
|
||||
.cfi_adjust_cfa_offset 4
|
||||
.cfi_rel_offset ebx, 0
|
||||
|
||||
/* The syscall calling convention isn't the same as the C one:
|
||||
* we enter with 0(%esp) == return address
|
||||
* 4(%esp) == *signal_pending
|
||||
* 8(%esp) == syscall number
|
||||
* 12(%esp) ... 32(%esp) == syscall arguments
|
||||
* and return the result in eax
|
||||
* and the syscall instruction needs
|
||||
* eax == syscall number
|
||||
* ebx, ecx, edx, esi, edi, ebp == syscall arguments
|
||||
* and returns the result in eax
|
||||
* Shuffle everything around appropriately.
|
||||
* Note the 16 bytes that we pushed to save registers.
|
||||
*/
|
||||
mov 12+16(%esp), %ebx /* the syscall arguments */
|
||||
mov 16+16(%esp), %ecx
|
||||
mov 20+16(%esp), %edx
|
||||
mov 24+16(%esp), %esi
|
||||
mov 28+16(%esp), %edi
|
||||
mov 32+16(%esp), %ebp
|
||||
|
||||
/* This next sequence of code works in conjunction with the
|
||||
* rewind_if_safe_syscall_function(). If a signal is taken
|
||||
* and the interrupted PC is anywhere between 'safe_syscall_start'
|
||||
* and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
|
||||
* The code sequence must therefore be able to cope with this, and
|
||||
* the syscall instruction must be the final one in the sequence.
|
||||
*/
|
||||
safe_syscall_start:
|
||||
/* if signal_pending is non-zero, don't do the call */
|
||||
mov 4+16 (%esp), %eax /* signal_pending */
|
||||
cmpl $0, (%eax)
|
||||
jnz 1f
|
||||
mov 8+16(%esp), %eax /* syscall number */
|
||||
int $0x80
|
||||
safe_syscall_end:
|
||||
/* code path for having successfully executed the syscall */
|
||||
/* Begin FreeBSD */
|
||||
jnb 2f
|
||||
neg %eax
|
||||
2:
|
||||
/* End FreeBSD */
|
||||
pop %ebx
|
||||
.cfi_remember_state
|
||||
.cfi_adjust_cfa_offset -4
|
||||
.cfi_restore ebx
|
||||
pop %edi
|
||||
.cfi_adjust_cfa_offset -4
|
||||
.cfi_restore edi
|
||||
pop %esi
|
||||
.cfi_adjust_cfa_offset -4
|
||||
.cfi_restore esi
|
||||
pop %ebp
|
||||
.cfi_adjust_cfa_offset -4
|
||||
.cfi_restore ebp
|
||||
ret
|
||||
|
||||
1:
|
||||
/* code path when we didn't execute the syscall */
|
||||
.cfi_restore_state
|
||||
mov $-TARGET_ERESTARTSYS, %eax
|
||||
jmp safe_syscall_end
|
||||
ret
|
||||
.cfi_endproc
|
||||
|
||||
.size safe_syscall_base, .-safe_syscall_base
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* hostdep.h : things which are dependent on the host architecture
|
||||
*
|
||||
* * Written by Peter Maydell <peter.maydell@linaro.org>
|
||||
*
|
||||
* Copyright (C) 2016 Linaro Limited
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef MIPS_HOSTDEP_H
|
||||
#define MIPS_HOSTDEP_H
|
||||
|
||||
#endif
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* hostdep.h : things which are dependent on the host architecture
|
||||
*
|
||||
* * Written by Peter Maydell <peter.maydell@linaro.org>
|
||||
*
|
||||
* Copyright (C) 2016 Linaro Limited
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef PPC_HOSTDEP_H
|
||||
#define PPC_HOSTDEP_H
|
||||
|
||||
#endif
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* hostdep.h : things which are dependent on the host architecture
|
||||
*
|
||||
* * Written by Peter Maydell <peter.maydell@linaro.org>
|
||||
*
|
||||
* Copyright (C) 2016 Linaro Limited
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef PPC64_HOSTDEP_H
|
||||
#define PPC64_HOSTDEP_H
|
||||
|
||||
/* We have a safe-syscall.inc.S */
|
||||
#define HAVE_SAFE_SYSCALL
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
/* These are defined by the safe-syscall.inc.S file */
|
||||
extern char safe_syscall_start[];
|
||||
extern char safe_syscall_end[];
|
||||
|
||||
/* FreeBSD-ism */
|
||||
#define DEFINE_PCREG(puc) &((ucontext_t *)(puc))->uc_mcontext.mc_srr0
|
||||
|
||||
/* Adjust the signal context to rewind out of safe-syscall if we're in it */
|
||||
static inline void rewind_if_in_safe_syscall(void *puc)
|
||||
{
|
||||
unsigned long *pcreg = DEFINE_PCREG(puc);
|
||||
|
||||
if (*pcreg > (uintptr_t)safe_syscall_start
|
||||
&& *pcreg < (uintptr_t)safe_syscall_end) {
|
||||
*pcreg = (uintptr_t)safe_syscall_start;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
#endif
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* safe-syscall.inc.S : host-specific assembly fragment
|
||||
* to handle signals occurring at the same time as system calls.
|
||||
* This is intended to be included by linux-user/safe-syscall.S
|
||||
*
|
||||
* Written by Richard Henderson <rth@twiddle.net>
|
||||
* Copyright (C) 2016 Red Hat, Inc.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
.global safe_syscall_base
|
||||
.global safe_syscall_start
|
||||
.global safe_syscall_end
|
||||
.type safe_syscall_base, @function
|
||||
|
||||
.text
|
||||
|
||||
/* This is the entry point for making a system call. The calling
|
||||
* convention here is that of a C varargs function with the
|
||||
* first argument an 'int *' to the signal_pending flag, the
|
||||
* second one the system call number (as a 'long'), and all further
|
||||
* arguments being syscall arguments (also 'long').
|
||||
* We return a long which is the syscall's return value, which
|
||||
* may be negative-errno on failure. Conversion to the
|
||||
* -1-and-errno-set convention is done by the calling wrapper.
|
||||
*/
|
||||
#if _CALL_ELF == 2
|
||||
safe_syscall_base:
|
||||
.cfi_startproc
|
||||
.localentry safe_syscall_base,0
|
||||
#else
|
||||
.section ".opd","aw"
|
||||
.align 3
|
||||
safe_syscall_base:
|
||||
.quad .L.safe_syscall_base,.TOC.@tocbase,0
|
||||
.previous
|
||||
.L.safe_syscall_base:
|
||||
.cfi_startproc
|
||||
#endif
|
||||
/* We enter with r3 == *signal_pending
|
||||
* r4 == syscall number
|
||||
* r5 ... r10 == syscall arguments
|
||||
* and return the result in r3
|
||||
* and the syscall instruction needs
|
||||
* r0 == syscall number
|
||||
* r3 ... r8 == syscall arguments
|
||||
* and returns the result in r3
|
||||
* Shuffle everything around appropriately.
|
||||
*/
|
||||
std 14, 16(1) /* Preserve r14 in SP+16 */
|
||||
.cfi_offset 14, 16
|
||||
mr 14, 3 /* signal_pending */
|
||||
mr 0, 4 /* syscall number */
|
||||
mr 3, 5 /* syscall arguments */
|
||||
mr 4, 6
|
||||
mr 5, 7
|
||||
mr 6, 8
|
||||
mr 7, 9
|
||||
mr 8, 10
|
||||
|
||||
/* This next sequence of code works in conjunction with the
|
||||
* rewind_if_safe_syscall_function(). If a signal is taken
|
||||
* and the interrupted PC is anywhere between 'safe_syscall_start'
|
||||
* and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
|
||||
* The code sequence must therefore be able to cope with this, and
|
||||
* the syscall instruction must be the final one in the sequence.
|
||||
*/
|
||||
safe_syscall_start:
|
||||
/* if signal_pending is non-zero, don't do the call */
|
||||
lwz 12, 0(14)
|
||||
cmpwi 0, 12, 0
|
||||
bne- 0f
|
||||
sc
|
||||
safe_syscall_end:
|
||||
/* code path when we did execute the syscall */
|
||||
ld 14, 16(1) /* restore r14 to its original value */
|
||||
bnslr+
|
||||
|
||||
/* syscall failed; return negative errno */
|
||||
neg 3, 3
|
||||
blr
|
||||
|
||||
/* code path when we didn't execute the syscall */
|
||||
0: addi 3, 0, -TARGET_ERESTARTSYS
|
||||
ld 14, 16(1) /* restore r14 to its orginal value */
|
||||
blr
|
||||
.cfi_endproc
|
||||
|
||||
#if _CALL_ELF == 2
|
||||
.size safe_syscall_base, .-safe_syscall_base
|
||||
#else
|
||||
.size safe_syscall_base, .-.L.safe_syscall_base
|
||||
.size .L.safe_syscall_base, .-.L.safe_syscall_base
|
||||
#endif
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* hostdep.h : things which are dependent on the host architecture
|
||||
*
|
||||
* * Written by Peter Maydell <peter.maydell@linaro.org>
|
||||
*
|
||||
* Copyright (C) 2016 Linaro Limited
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef X86_64_HOSTDEP_H
|
||||
#define X86_64_HOSTDEP_H
|
||||
|
||||
/* We have a safe-syscall.inc.S */
|
||||
#define HAVE_SAFE_SYSCALL
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
/* These are defined by the safe-syscall.inc.S file */
|
||||
extern char safe_syscall_start[];
|
||||
extern char safe_syscall_end[];
|
||||
|
||||
/* FreeBSD-isms */
|
||||
typedef __register_t greg_t;
|
||||
#define DEFINE_PCREG(puc) &((ucontext_t *)(puc))->uc_mcontext.mc_rip
|
||||
|
||||
/* Adjust the signal context to rewind out of safe-syscall if we're in it */
|
||||
static inline void rewind_if_in_safe_syscall(void *puc)
|
||||
{
|
||||
greg_t *pcreg = DEFINE_PCREG(puc);
|
||||
|
||||
if (*pcreg > (uintptr_t)safe_syscall_start
|
||||
&& *pcreg < (uintptr_t)safe_syscall_end) {
|
||||
*pcreg = (uintptr_t)safe_syscall_start;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
#endif
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* safe-syscall.inc.S : host-specific assembly fragment
|
||||
* to handle signals occurring at the same time as system calls.
|
||||
* This is intended to be included by linux-user/safe-syscall.S
|
||||
*
|
||||
* Copyright (C) 2015 Timothy Edward Baldwin <T.E.Baldwin99@members.leeds.ac.uk>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
.global safe_syscall_base
|
||||
.global safe_syscall_start
|
||||
.global safe_syscall_end
|
||||
.type safe_syscall_base, @function
|
||||
|
||||
/* This is the entry point for making a system call. The calling
|
||||
* convention here is that of a C varargs function with the
|
||||
* first argument an 'int *' to the signal_pending flag, the
|
||||
* second one the system call number (as a 'long'), and all further
|
||||
* arguments being syscall arguments (also 'long').
|
||||
* We return a long which is the syscall's return value, which
|
||||
* may be negative-errno on failure. Conversion to the
|
||||
* -1-and-errno-set convention is done by the calling wrapper.
|
||||
*/
|
||||
safe_syscall_base:
|
||||
.cfi_startproc
|
||||
/* This saves a frame pointer and aligns the stack for the syscall.
|
||||
* (It's unclear if the syscall ABI has the same stack alignment
|
||||
* requirements as the userspace function call ABI, but better safe than
|
||||
* sorry. Appendix A2 of http://www.x86-64.org/documentation/abi.pdf
|
||||
* does not list any ABI differences regarding stack alignment.)
|
||||
*/
|
||||
push %rbp
|
||||
.cfi_adjust_cfa_offset 8
|
||||
.cfi_rel_offset rbp, 0
|
||||
|
||||
/* The syscall calling convention isn't the same as the
|
||||
* C one:
|
||||
* we enter with rdi == *signal_pending
|
||||
* rsi == syscall number
|
||||
* rdx, rcx, r8, r9, (stack), (stack) == syscall arguments
|
||||
* and return the result in rax
|
||||
* and the syscall instruction needs
|
||||
* rax == syscall number
|
||||
* rdi, rsi, rdx, r10, r8, r9 == syscall arguments
|
||||
* and returns the result in rax
|
||||
* Shuffle everything around appropriately.
|
||||
* Note that syscall will trash rcx and r11.
|
||||
*/
|
||||
mov %rsi, %rax /* syscall number */
|
||||
mov %rdi, %rbp /* signal_pending pointer */
|
||||
/* and the syscall arguments */
|
||||
mov %rdx, %rdi
|
||||
mov %rcx, %rsi
|
||||
mov %r8, %rdx
|
||||
mov %r9, %r10
|
||||
mov 16(%rsp), %r8
|
||||
mov 24(%rsp), %r9
|
||||
|
||||
/* This next sequence of code works in conjunction with the
|
||||
* rewind_if_safe_syscall_function(). If a signal is taken
|
||||
* and the interrupted PC is anywhere between 'safe_syscall_start'
|
||||
* and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
|
||||
* The code sequence must therefore be able to cope with this, and
|
||||
* the syscall instruction must be the final one in the sequence.
|
||||
*/
|
||||
safe_syscall_start:
|
||||
/* if signal_pending is non-zero, don't do the call */
|
||||
cmpl $0, (%rbp)
|
||||
jnz 1f
|
||||
syscall
|
||||
safe_syscall_end:
|
||||
/* code path for having successfully executed the syscall */
|
||||
/* Begin FreeBSD */
|
||||
jnb 2f
|
||||
neg %rax
|
||||
2:
|
||||
/* End FreeBSD */
|
||||
pop %rbp
|
||||
.cfi_remember_state
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_restore rbp
|
||||
ret
|
||||
|
||||
1:
|
||||
/* code path when we didn't execute the syscall */
|
||||
.cfi_restore_state
|
||||
mov $-TARGET_ERESTARTSYS, %rax
|
||||
pop %rbp
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_restore rbp
|
||||
ret
|
||||
.cfi_endproc
|
||||
|
||||
.size safe_syscall_base, .-safe_syscall_base
|
|
@ -24,7 +24,6 @@
|
|||
#include <sys/sysctl.h>
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qemu/accel.h"
|
||||
#include "sysemu/tcg.h"
|
||||
|
@ -33,8 +32,8 @@
|
|||
|
||||
#include "qapi/error.h"
|
||||
#include "qemu.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/path.h"
|
||||
#include "qemu/help_option.h"
|
||||
#include "qemu/module.h"
|
||||
|
@ -45,14 +44,20 @@
|
|||
#include "qemu/cutils.h"
|
||||
#include "exec/log.h"
|
||||
#include "trace/control.h"
|
||||
#include "crypto/init.h"
|
||||
#include "qemu/guest-random.h"
|
||||
|
||||
#include "host-os.h"
|
||||
#include "target_arch_cpu.h"
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
pthread_mutex_t ras_mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_cond_t ras_cond = PTHREAD_COND_INITIALIZER;
|
||||
pthread_t ras_thread;
|
||||
bool ras_thread_set = false;
|
||||
#endif
|
||||
int singlestep;
|
||||
uintptr_t guest_base;
|
||||
static const char *cpu_model;
|
||||
static const char *cpu_type;
|
||||
bool have_guest_base;
|
||||
/*
|
||||
* When running 32-on-64 we should make sure we can fit all of the possible
|
||||
|
@ -94,7 +99,7 @@ unsigned long reserved_va = MAX_RESERVED_VA;
|
|||
unsigned long reserved_va;
|
||||
#endif
|
||||
|
||||
static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
|
||||
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 */
|
||||
|
@ -226,6 +231,36 @@ void init_task_state(TaskState *ts)
|
|||
ts->sigqueue_table[i].next = NULL;
|
||||
}
|
||||
|
||||
CPUArchState *cpu_copy(CPUArchState *env)
|
||||
{
|
||||
CPUState *cpu = env_cpu(env);
|
||||
CPUState *new_cpu = cpu_create(cpu_type);
|
||||
CPUArchState *new_env = new_cpu->env_ptr;
|
||||
CPUBreakpoint *bp;
|
||||
CPUWatchpoint *wp;
|
||||
|
||||
/* Reset non arch specific state */
|
||||
cpu_reset(new_cpu);
|
||||
|
||||
memcpy(new_env, env, sizeof(CPUArchState));
|
||||
|
||||
/*
|
||||
* Clone all break/watchpoints.
|
||||
* Note: Once we support ptrace with hw-debug register access, make sure
|
||||
* BP_CPU break/watchpoints are handled correctly on clone.
|
||||
*/
|
||||
QTAILQ_INIT(&cpu->breakpoints);
|
||||
QTAILQ_INIT(&cpu->watchpoints);
|
||||
QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
|
||||
cpu_breakpoint_insert(new_cpu, bp->pc, bp->flags, NULL);
|
||||
}
|
||||
QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
|
||||
cpu_watchpoint_insert(new_cpu, wp->vaddr, wp->len, wp->flags, NULL);
|
||||
}
|
||||
|
||||
return new_env;
|
||||
}
|
||||
|
||||
void gemu_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
@ -271,11 +306,8 @@ static void save_proc_pathname(char *argv0)
|
|||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *filename;
|
||||
const char *cpu_model;
|
||||
const char *cpu_type;
|
||||
const char *log_file = NULL;
|
||||
const char *log_mask = NULL;
|
||||
const char *seed_optarg = NULL;
|
||||
struct target_pt_regs regs1, *regs = ®s1;
|
||||
struct image_info info1, *info = &info1;
|
||||
struct bsd_binprm bprm;
|
||||
|
@ -298,7 +330,6 @@ int main(int argc, char **argv)
|
|||
|
||||
save_proc_pathname(argv[0]);
|
||||
|
||||
error_init(argv[0]);
|
||||
module_call_init(MODULE_INIT_TRACE);
|
||||
qemu_init_cpu_list();
|
||||
module_call_init(MODULE_INIT_QOM);
|
||||
|
@ -405,8 +436,6 @@ int main(int argc, char **argv)
|
|||
usage();
|
||||
}
|
||||
optind++;
|
||||
} else if (!strcmp(r, "seed")) {
|
||||
seed_optarg = optarg;
|
||||
} else if (!strcmp(r, "singlestep")) {
|
||||
singlestep = 1;
|
||||
} else if (!strcmp(r, "strace")) {
|
||||
|
@ -421,8 +450,10 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
/* init debug */
|
||||
qemu_log_needs_buffers();
|
||||
qemu_set_log_filename(log_file, &error_fatal);
|
||||
if (log_file) {
|
||||
qemu_log_needs_buffers();
|
||||
qemu_set_log_filename(log_file, &error_fatal);
|
||||
}
|
||||
if (log_mask) {
|
||||
int mask;
|
||||
|
||||
|
@ -472,6 +503,7 @@ int main(int argc, char **argv)
|
|||
accel_init_interfaces(ac);
|
||||
ac->init_machine(NULL);
|
||||
}
|
||||
|
||||
cpu = cpu_create(cpu_type);
|
||||
env = cpu->env_ptr;
|
||||
cpu_reset(cpu);
|
||||
|
@ -488,19 +520,6 @@ int main(int argc, char **argv)
|
|||
mmap_next_start = reserved_va;
|
||||
}
|
||||
|
||||
{
|
||||
Error *err = NULL;
|
||||
if (seed_optarg != NULL) {
|
||||
qemu_guest_random_seed_main(seed_optarg, &err);
|
||||
} else {
|
||||
qcrypto_init(&err);
|
||||
}
|
||||
if (err) {
|
||||
error_reportf_err(err, "cannot initialize crypto: ");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now that page sizes are configured we can do
|
||||
* proper page alignment for guest_base.
|
||||
|
|
|
@ -3,10 +3,16 @@ if not have_bsd_user
|
|||
endif
|
||||
|
||||
bsd_user_ss.add(files(
|
||||
'bsd-ioctl.c',
|
||||
'bsd-mem.c',
|
||||
'bsd-misc.c',
|
||||
'bsd-proc.c',
|
||||
'bsd-socket.c',
|
||||
'bsdload.c',
|
||||
'elfload.c',
|
||||
'main.c',
|
||||
'mmap.c',
|
||||
'safe-syscall.S',
|
||||
'signal.c',
|
||||
'strace.c',
|
||||
'syscall.c',
|
||||
|
@ -15,3 +21,6 @@ bsd_user_ss.add(files(
|
|||
|
||||
# Pull in the OS-specific build glue, if any
|
||||
subdir(targetos)
|
||||
elf = cc.find_library('elf', required: true)
|
||||
procstat = cc.find_library('procstat', required: true)
|
||||
bsd_user_ss.add(elf, procstat)
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* mips specific prototypes for bsd-user
|
||||
*
|
||||
* 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 _TARGET_ARCH_H_
|
||||
#define _TARGET_ARCH_H_
|
||||
|
||||
#include "qemu.h"
|
||||
|
||||
void target_cpu_set_tls(CPUMIPSState *env, target_ulong newtls);
|
||||
target_ulong target_cpu_get_tls(CPUMIPSState *env);
|
||||
|
||||
#endif /* !_TARGET_ARCH_H_ */
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* mips cpu related code
|
||||
*
|
||||
* 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 "target_arch.h"
|
||||
|
||||
#define TP_OFFSET 0x7008
|
||||
|
||||
void target_cpu_set_tls(CPUMIPSState *env, target_ulong newtls)
|
||||
{
|
||||
env->active_tc.CP0_UserLocal = newtls + TP_OFFSET;
|
||||
}
|
||||
|
||||
target_ulong target_cpu_get_tls(CPUMIPSState *env)
|
||||
{
|
||||
return (env->active_tc.CP0_UserLocal - TP_OFFSET);
|
||||
}
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* mips cpu init and loop
|
||||
*
|
||||
* 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 _TARGET_ARCH_CPU_H_
|
||||
#define _TARGET_ARCH_CPU_H_
|
||||
|
||||
#include "target_arch.h"
|
||||
|
||||
#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSO32)
|
||||
# define TARGET_DEFAULT_CPU_MODEL "24Kc"
|
||||
#else
|
||||
# define TARGET_DEFAULT_CPU_MODEL "24Kf"
|
||||
#endif
|
||||
|
||||
#define TARGET_CPU_RESET(cpu)
|
||||
|
||||
static inline void target_cpu_init(CPUMIPSState *env,
|
||||
struct target_pt_regs *regs)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
env->active_tc.gpr[i] = regs->regs[i];
|
||||
}
|
||||
env->active_tc.PC = regs->cp0_epc & ~(target_ulong)1;
|
||||
if (regs->cp0_epc & 1) {
|
||||
env->hflags |= MIPS_HFLAG_M16;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void target_cpu_loop(CPUMIPSState *env)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
target_siginfo_t info;
|
||||
int trapnr;
|
||||
abi_long ret;
|
||||
unsigned int syscall_num;
|
||||
|
||||
for (;;) {
|
||||
cpu_exec_start(cs);
|
||||
trapnr = cpu_exec(cs);
|
||||
cpu_exec_end(cs);
|
||||
process_queued_cpu_work(cs);
|
||||
switch (trapnr) {
|
||||
case EXCP_SYSCALL: /* syscall exception */
|
||||
if (bsd_type == target_freebsd) {
|
||||
syscall_num = env->active_tc.gpr[2]; /* v0 */
|
||||
env->active_tc.PC += TARGET_INSN_SIZE;
|
||||
if (syscall_num >= TARGET_FREEBSD_NR_MAXSYSCALL) {
|
||||
ret = -TARGET_ENOSYS;
|
||||
} else {
|
||||
abi_ulong arg4 = 0, arg5 = 0, arg6 = 0, arg7 =0;
|
||||
abi_ulong sp_reg = env->active_tc.gpr[29];
|
||||
|
||||
# ifdef TARGET_ABI_MIPSO32
|
||||
get_user_ual(arg4, sp_reg + 16);
|
||||
get_user_ual(arg5, sp_reg + 20);
|
||||
get_user_ual(arg6, sp_reg + 24);
|
||||
get_user_ual(arg7, sp_reg + 28);
|
||||
#else
|
||||
arg4 = env->active_tc.gpr[12]; /* t4/arg4 */
|
||||
arg5 = env->active_tc.gpr[13]; /* t5/arg5 */
|
||||
arg6 = env->active_tc.gpr[14]; /* t6/arg6 */
|
||||
arg7 = env->active_tc.gpr[15]; /* t7/arg7 */
|
||||
#endif
|
||||
/* mips(32) uses regs 4-7,12-15 for args */
|
||||
if (TARGET_FREEBSD_NR___syscall == syscall_num ||
|
||||
TARGET_FREEBSD_NR_syscall == syscall_num) {
|
||||
/* indirect syscall */
|
||||
ret = do_freebsd_syscall(env,
|
||||
env->active_tc.gpr[4],/* syscall #*/
|
||||
env->active_tc.gpr[5], /* a1/arg0 */
|
||||
env->active_tc.gpr[6], /* a2/arg1 */
|
||||
env->active_tc.gpr[7], /* a3/arg2 */
|
||||
arg4,
|
||||
arg5,
|
||||
arg6,
|
||||
arg7,
|
||||
0 /* no arg7 */
|
||||
);
|
||||
} else {
|
||||
/* direct syscall */
|
||||
ret = do_freebsd_syscall(env,
|
||||
syscall_num,
|
||||
env->active_tc.gpr[4], /* a0/arg0 */
|
||||
env->active_tc.gpr[5], /* a1/arg1 */
|
||||
env->active_tc.gpr[6], /* a2/arg2 */
|
||||
env->active_tc.gpr[7], /* a3/arg3 */
|
||||
arg4,
|
||||
arg5,
|
||||
arg6,
|
||||
arg7
|
||||
);
|
||||
}
|
||||
}
|
||||
/* Compare to mips/mips/vm_machdep.c cpu_set_syscall_retval() */
|
||||
if (-TARGET_EJUSTRETURN == ret) {
|
||||
/*
|
||||
* Returning from a successful sigreturn
|
||||
* syscall. Avoid clobbering register state.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
if (-TARGET_ERESTART == ret) {
|
||||
/* Backup the pc to point at the swi. */
|
||||
env->active_tc.PC -= TARGET_INSN_SIZE;
|
||||
break;
|
||||
}
|
||||
if ((unsigned int)ret >= (unsigned int)(-1133)) {
|
||||
env->active_tc.gpr[7] = 1;
|
||||
ret = -ret;
|
||||
} else {
|
||||
env->active_tc.gpr[7] = 0;
|
||||
}
|
||||
env->active_tc.gpr[2] = ret; /* v0 <- ret */
|
||||
} /* else if (bsd_type == target_openbsd)... */
|
||||
else {
|
||||
fprintf(stderr, "qemu: bsd_type (= %d) syscall not supported\n",
|
||||
bsd_type);
|
||||
}
|
||||
break;
|
||||
|
||||
case EXCP_TLBL: /* TLB miss on load */
|
||||
case EXCP_TLBS: /* TLB miss on store */
|
||||
case EXCP_AdEL: /* bad address on load */
|
||||
case EXCP_AdES: /* bad address on store */
|
||||
info.target_si_signo = TARGET_SIGSEGV;
|
||||
info.target_si_errno = 0;
|
||||
/* XXX: check env->error_code */
|
||||
info.target_si_code = TARGET_SEGV_MAPERR;
|
||||
info.target_si_addr = env->CP0_BadVAddr;
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
break;
|
||||
|
||||
case EXCP_CpU: /* coprocessor unusable */
|
||||
case EXCP_RI: /* reserved instruction */
|
||||
info.target_si_signo = TARGET_SIGILL;
|
||||
info.target_si_errno = 0;
|
||||
info.target_si_code = 0;
|
||||
queue_signal(env, info.target_si_signo, &info);
|
||||
break;
|
||||
|
||||
case EXCP_INTERRUPT: /* async interrupt */
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
|
||||
case EXCP_DEBUG: /* cpu stopped after a breakpoint */
|
||||
{
|
||||
|
||||
info.target_si_signo = TARGET_SIGTRAP;
|
||||
info.target_si_errno = 0;
|
||||
info.target_si_code = TARGET_TRAP_BRKPT;
|
||||
queue_signal(env, info.target_si_signo, &info);
|
||||
}
|
||||
break;
|
||||
|
||||
case EXCP_ATOMIC:
|
||||
cpu_exec_step_atomic(cs);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "qemu: unhandled CPU exception "
|
||||
"0x%x - aborting\n", trapnr);
|
||||
cpu_dump_state(cs, stderr, 0);
|
||||
abort();
|
||||
}
|
||||
process_pending_signals(env);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void target_cpu_clone_regs(CPUMIPSState *env, target_ulong newsp)
|
||||
{
|
||||
if (newsp)
|
||||
env->active_tc.gpr[29] = newsp;
|
||||
env->active_tc.gpr[7] = 0;
|
||||
env->active_tc.gpr[2] = 0;
|
||||
}
|
||||
|
||||
static inline void target_cpu_reset(CPUArchState *cpu)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* ! _TARGET_ARCH_CPU_H_ */
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* mips ELF 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 _TARGET_ARCH_ELF_H_
|
||||
#define _TARGET_ARCH_ELF_H_
|
||||
|
||||
#define elf_check_arch(x) ( (x) == EM_MIPS )
|
||||
#define ELF_START_MMAP 0x80000000
|
||||
#define ELF_ET_DYN_LOAD_ADDR 0x0120000
|
||||
#define ELF_CLASS ELFCLASS32
|
||||
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
#define ELF_DATA ELFDATA2MSB
|
||||
#else
|
||||
#define ELF_DATA ELFDATA2LSB
|
||||
#endif
|
||||
#define ELF_ARCH EM_MIPS
|
||||
|
||||
#define USE_ELF_CORE_DUMP
|
||||
#define ELF_EXEC_PAGESIZE 4096
|
||||
|
||||
#endif /* _TARGET_ARCH_ELF_H_ */
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* FreeBSD mips register structures
|
||||
*
|
||||
* Copyright (c) 2015 Stacey Son
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 _TARGET_ARCH_REG_H_
|
||||
#define _TARGET_ARCH_REG_H_
|
||||
|
||||
/* See sys/mips/include/reg.h */
|
||||
#define TARGET_NUMSAVEREGS 40
|
||||
typedef struct target_reg {
|
||||
uint32_t r_regs[TARGET_NUMSAVEREGS];
|
||||
} target_reg_t;
|
||||
|
||||
#define TARGET_NUMFPREGS 34
|
||||
typedef struct target_fpreg {
|
||||
uint32_t r_regs[TARGET_NUMFPREGS];
|
||||
} target_fpreg_t;
|
||||
|
||||
#ifdef TARGET_ABI_MIPSN32
|
||||
#define tswapreg(ptr) tswap64(ptr)
|
||||
#else
|
||||
#define tswapreg(ptr) tswapal(ptr)
|
||||
#endif
|
||||
|
||||
static inline void target_copy_regs(target_reg_t *regs, const CPUMIPSState *env)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* See sys/mips/include/frame.h struct trapframe or
|
||||
* sys/mips/include/regnum.h for register order.
|
||||
*/
|
||||
for (i = 0; i < 32; i++)
|
||||
regs->r_regs[i] = tswapreg(env->active_tc.gpr[i]);
|
||||
regs->r_regs[32] = tswapreg(env->CP0_Status); /* sr */
|
||||
regs->r_regs[33] = tswapreg(env->active_tc.LO[0]); /* mullo */
|
||||
regs->r_regs[34] = tswapreg(env->active_tc.HI[0]); /* mulhi */
|
||||
regs->r_regs[35] = tswapreg(env->CP0_BadVAddr);
|
||||
regs->r_regs[36] = tswapreg(env->CP0_Cause);
|
||||
regs->r_regs[37] = tswapreg(env->active_tc.PC);
|
||||
regs->r_regs[38] = 0; /* ic (RM7k and RM9k specific) */
|
||||
regs->r_regs[39] = 0; /* Dummy for 8 byte alignment */
|
||||
}
|
||||
|
||||
#undef tswapreg
|
||||
|
||||
#endif /* !_TARGET_ARCH_REG_H_ */
|
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
* mips signal definitions
|
||||
*
|
||||
*
|
||||
* 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 _TARGET_ARCH_SIGNAL_H_
|
||||
#define _TARGET_ARCH_SIGNAL_H_
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
#define TARGET_INSN_SIZE 4 /* mips instruction size */
|
||||
|
||||
/* Size of the signal trampolin code. See insall_sigtramp(). */
|
||||
#define TARGET_SZSIGCODE ((abi_ulong)(4 * TARGET_INSN_SIZE))
|
||||
|
||||
/* compare to mips/include/_limits.h */
|
||||
#define TARGET_MINSIGSTKSZ (512 * 4) /* min sig stack size */
|
||||
#define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) /* recommended size */
|
||||
|
||||
/* compare to sys/mips/include/asm.h */
|
||||
#define TARGET_SZREG 8
|
||||
#define TARGET_CALLFRAME_SIZ (TARGET_SZREG * 4)
|
||||
|
||||
/* mips/mips/pm_machdep.c */
|
||||
#define TARGET_UCONTEXT_MAGIC 0xACEDBADE
|
||||
#define TARGET_MC_GET_CLEAR_RET 0x0001
|
||||
#define TARGET_MC_ADD_MAGIC 0x0002
|
||||
#define TARGET_MC_SET_ONSTACK 0x0004
|
||||
|
||||
struct target_sigcontext {
|
||||
target_sigset_t sc_mask; /* signal mask to retstore */
|
||||
int32_t sc_onstack; /* sigstack state to restore */
|
||||
abi_long sc_pc; /* pc at time of signal */
|
||||
abi_long sc_reg[32]; /* processor regs 0 to 31 */
|
||||
abi_long mullo, mulhi; /* mullo and mulhi registers */
|
||||
int32_t sc_fpused; /* fp has been used */
|
||||
abi_long sc_fpregs[33]; /* fp regs 0 to 31 & csr */
|
||||
abi_long sc_fpc_eir; /* fp exception instr reg */
|
||||
/* int32_t reserved[8]; */
|
||||
};
|
||||
|
||||
typedef struct target_mcontext {
|
||||
int32_t mc_onstack; /* sigstack state to restore */
|
||||
abi_long mc_pc; /* pc at time of signal */
|
||||
abi_long mc_regs[32]; /* process regs 0 to 31 */
|
||||
abi_long sr; /* status register */
|
||||
abi_long mullo, mulhi;
|
||||
int32_t mc_fpused; /* fp has been used */
|
||||
abi_long mc_fpregs[33]; /* fp regs 0 to 32 & csr */
|
||||
abi_long mc_fpc_eir; /* fp exception instr reg */
|
||||
abi_ulong mc_tls; /* pointer to TLS area */
|
||||
} target_mcontext_t;
|
||||
|
||||
typedef struct target_ucontext {
|
||||
target_sigset_t uc_sigmask;
|
||||
target_mcontext_t uc_mcontext;
|
||||
abi_ulong uc_link;
|
||||
target_stack_t uc_stack;
|
||||
int32_t uc_flags;
|
||||
int32_t __spare__[4];
|
||||
} target_ucontext_t;
|
||||
|
||||
struct target_sigframe {
|
||||
abi_ulong sf_signum;
|
||||
abi_ulong sf_siginfo; /* code or pointer to sf_si */
|
||||
abi_ulong sf_ucontext; /* points to sf_uc */
|
||||
abi_ulong sf_addr; /* undocumented 4th arg */
|
||||
target_ucontext_t sf_uc; /* = *sf_uncontext */
|
||||
target_siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
|
||||
uint32_t __spare__[2];
|
||||
};
|
||||
|
||||
/* Forward declare due to unfortunate header nesting */
|
||||
void target_cpu_set_tls(CPUMIPSState *env, target_ulong newtls);
|
||||
target_ulong target_cpu_get_tls(CPUMIPSState *env);
|
||||
|
||||
/*
|
||||
* Compare to mips/mips/pm_machdep.c sendsig()
|
||||
* Assumes that target stack frame memory is locked.
|
||||
*/
|
||||
static inline abi_long
|
||||
set_sigtramp_args(CPUMIPSState *regs, int sig, struct target_sigframe *frame,
|
||||
abi_ulong frame_addr, struct target_sigaction *ka)
|
||||
{
|
||||
|
||||
/* frame->sf_si.si_addr = regs->CP0_BadVAddr; */
|
||||
|
||||
/* MIPS only struct target_sigframe members: */
|
||||
frame->sf_signum = sig;
|
||||
frame->sf_siginfo = frame_addr + offsetof(struct target_sigframe, sf_si);
|
||||
frame->sf_ucontext = frame_addr + offsetof(struct target_sigframe, sf_uc);
|
||||
|
||||
/*
|
||||
* Arguments to signal handler:
|
||||
* a0 ($4) = signal number
|
||||
* a1 ($5) = siginfo pointer
|
||||
* a2 ($6) = ucontext pointer
|
||||
* PC = signal handler pointer
|
||||
* t9 ($25) = signal handler pointer
|
||||
* $29 = point to sigframe struct
|
||||
* ra ($31) = sigtramp at base of user stack
|
||||
*/
|
||||
regs->active_tc.gpr[4] = sig;
|
||||
regs->active_tc.gpr[5] = frame_addr +
|
||||
offsetof(struct target_sigframe, sf_si);
|
||||
regs->active_tc.gpr[6] = frame_addr +
|
||||
offsetof(struct target_sigframe, sf_uc);
|
||||
regs->active_tc.gpr[25] = regs->active_tc.PC = ka->_sa_handler;
|
||||
regs->active_tc.gpr[29] = frame_addr;
|
||||
regs->active_tc.gpr[31] = TARGET_PS_STRINGS - TARGET_SZSIGCODE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare to mips/mips/pm_machdep.c get_mcontext()
|
||||
* Assumes that the memory is locked if mcp points to user memory.
|
||||
*/
|
||||
static inline abi_long get_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp,
|
||||
int flags)
|
||||
{
|
||||
int i, err = 0;
|
||||
|
||||
if (flags & TARGET_MC_ADD_MAGIC) {
|
||||
mcp->mc_regs[0] = tswapal(TARGET_UCONTEXT_MAGIC);
|
||||
} else {
|
||||
mcp->mc_regs[0] = 0;
|
||||
}
|
||||
|
||||
if (flags & TARGET_MC_SET_ONSTACK) {
|
||||
mcp->mc_onstack = tswapal(1);
|
||||
} else {
|
||||
mcp->mc_onstack = 0;
|
||||
}
|
||||
|
||||
for (i = 1; i < 32; i++) {
|
||||
mcp->mc_regs[i] = tswapal(regs->active_tc.gpr[i]);
|
||||
}
|
||||
|
||||
#if 0 /* XXX FP is not used right now */
|
||||
abi_ulong used_fp = used_math() ? TARGET_MDTD_FPUSED : 0;
|
||||
|
||||
mcp->mc_fpused = used_fp;
|
||||
if (used_fp) {
|
||||
preempt_disable();
|
||||
if (!is_fpu_owner()) {
|
||||
own_fpu();
|
||||
for (i = 0; i < 33; i++) {
|
||||
mcp->mc_fpregs[i] = tswapal(regs->active_fpu.fpr[i]);
|
||||
}
|
||||
}
|
||||
preempt_enable();
|
||||
}
|
||||
#else
|
||||
mcp->mc_fpused = 0;
|
||||
#endif
|
||||
|
||||
if (flags & TARGET_MC_GET_CLEAR_RET) {
|
||||
mcp->mc_regs[2] = 0; /* v0 = 0 */
|
||||
mcp->mc_regs[3] = 0; /* v1 = 0 */
|
||||
mcp->mc_regs[7] = 0; /* a3 = 0 */
|
||||
}
|
||||
|
||||
mcp->mc_pc = tswapal(regs->active_tc.PC);
|
||||
mcp->mullo = tswapal(regs->active_tc.LO[0]);
|
||||
mcp->mulhi = tswapal(regs->active_tc.HI[0]);
|
||||
mcp->mc_tls = tswapal(target_cpu_get_tls(regs));
|
||||
|
||||
/* Don't do any of the status and cause registers. */
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Compare to mips/mips/pm_machdep.c set_mcontext() */
|
||||
static inline abi_long set_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp,
|
||||
int srflag)
|
||||
{
|
||||
int i, err = 0;
|
||||
|
||||
for (i = 1; i < 32; i++) {
|
||||
regs->active_tc.gpr[i] = tswapal(mcp->mc_regs[i]);
|
||||
}
|
||||
|
||||
#if 0 /* XXX FP is not used right now */
|
||||
abi_ulong used_fp = 0;
|
||||
|
||||
used_fp = tswapal(mcp->mc_fpused)
|
||||
conditional_used_math(used_fp);
|
||||
|
||||
preempt_disabled();
|
||||
if (used_math()) {
|
||||
/* restore fpu context if we have used it before */
|
||||
own_fpu();
|
||||
for (i = 0; i < 32; i++) {
|
||||
regs->active_fpu.fpr[i] = tswapal(mcp->mc_fpregs[i]);
|
||||
}
|
||||
} else {
|
||||
/* Signal handler may have used FPU. Give it up. */
|
||||
lose_fpu();
|
||||
}
|
||||
preempt_enable();
|
||||
#endif
|
||||
|
||||
regs->CP0_EPC = tswapal(mcp->mc_pc);
|
||||
regs->active_tc.LO[0] = tswapal(mcp->mullo);
|
||||
regs->active_tc.HI[0] = tswapal(mcp->mulhi);
|
||||
target_cpu_set_tls(regs, tswapal(mcp->mc_tls));
|
||||
|
||||
if (srflag) {
|
||||
/* doing sigreturn() */
|
||||
regs->active_tc.PC = regs->CP0_EPC;
|
||||
regs->CP0_EPC = 0; /* XXX for nested signals ? */
|
||||
}
|
||||
|
||||
/* Don't do any of the status and cause registers. */
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline abi_long get_ucontext_sigreturn(CPUMIPSState *regs,
|
||||
abi_ulong target_sf, abi_ulong *target_uc)
|
||||
{
|
||||
|
||||
*target_uc = target_sf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif /* !_TARGET_ARCH_SIGNAL_H_ */
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
#ifndef _TARGET_ARCH_SIGTRAMP_H_
|
||||
#define _TARGET_ARCH_SIGTRAMP_H_
|
||||
|
||||
/* Compare to mips/mips/locore.S sigcode() */
|
||||
static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
|
||||
unsigned sys_sigreturn)
|
||||
{
|
||||
int i;
|
||||
uint32_t sigtramp_code[TARGET_SZSIGCODE/TARGET_INSN_SIZE] = {
|
||||
/* 1 */ 0x27A40000 + sigf_uc, /* addu $a0, $sp, (sigf_uc) */
|
||||
/* 2 */ 0x24020000 + sys_sigreturn, /* li $v0, (sys_sigreturn) */
|
||||
/* 3 */ 0x0000000C, /* syscall */
|
||||
/* 4 */ 0x0000000D /* break */
|
||||
};
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
tswap32s(&sigtramp_code[i]);
|
||||
}
|
||||
|
||||
return memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE);
|
||||
}
|
||||
#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
|
|
@ -17,8 +17,8 @@
|
|||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef BSD_USER_ARCH_SYSARCH_H_
|
||||
#define BSD_USER_ARCH_SYSARCH_H_
|
||||
#ifndef __ARCH_SYSARCH_H_
|
||||
#define __ARCH_SYSARCH_H_
|
||||
|
||||
#include "target_syscall.h"
|
||||
#include "target_arch.h"
|
||||
|
@ -66,4 +66,4 @@ static inline void do_freebsd_arch_print_sysarch(
|
|||
}
|
||||
}
|
||||
|
||||
#endif /*!BSD_USER_ARCH_SYSARCH_H_ */
|
||||
#endif /*!__ARCH_SYSARCH_H_ */
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* mips thread support
|
||||
*
|
||||
* 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 _TARGET_ARCH_THREAD_H_
|
||||
#define _TARGET_ARCH_THREAD_H_
|
||||
|
||||
/* Compare to mips/mips/vm_machdep.c cpu_set_upcall_kse() */
|
||||
static inline void target_thread_set_upcall(CPUMIPSState *regs, abi_ulong entry,
|
||||
abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
|
||||
{
|
||||
abi_ulong sp;
|
||||
|
||||
/*
|
||||
* At the point where a function is called, sp must be 8
|
||||
* byte aligned[for compatibility with 64-bit CPUs]
|
||||
* in ``See MIPS Run'' by D. Sweetman, p. 269
|
||||
* align stack
|
||||
*/
|
||||
sp = ((stack_base + stack_size) & ~0x7) - TARGET_CALLFRAME_SIZ;
|
||||
|
||||
/* t9 = pc = start function entry */
|
||||
regs->active_tc.gpr[25] = regs->active_tc.PC = entry;
|
||||
/* a0 = arg */
|
||||
regs->active_tc.gpr[4] = arg;
|
||||
/* sp = top of the stack */
|
||||
regs->active_tc.gpr[29] = sp;
|
||||
}
|
||||
|
||||
static inline void target_thread_init(struct target_pt_regs *regs,
|
||||
struct image_info *infop)
|
||||
{
|
||||
regs->cp0_status = 2 << CP0St_KSU;
|
||||
regs->regs[25] = regs->cp0_epc = infop->entry & ~3; /* t9/pc = entry */
|
||||
regs->regs[4] = regs->regs[29] = infop->start_stack; /* a0/sp = stack */
|
||||
regs->regs[5] = regs->regs[6] = 0; /* a1/a2 = 0 */
|
||||
regs->regs[7] = TARGET_PS_STRINGS; /* a3 = ps_strings */
|
||||
}
|
||||
|
||||
#endif /* !_TARGET_ARCH_THREAD_H_ */
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* mips VM parameters 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 _TARGET_ARCH_VMPARAM_H_
|
||||
#define _TARGET_ARCH_VMPARAM_H_
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
/* compare to sys/mips/include/vmparam.h */
|
||||
#define TARGET_MAXTSIZ (128 * MiB) /* max text size */
|
||||
#define TARGET_DFLDSIZ (128 * MiB) /* initial data size limit */
|
||||
#define TARGET_MAXDSIZ (1 * GiB) /* max data size */
|
||||
#define TARGET_DFLSSIZ (8 * MiB) /* initial stack size limit */
|
||||
#define TARGET_MAXSSIZ (64 * MiB) /* max stack size */
|
||||
#define TARGET_SGROWSIZ (128 * KiB) /* amount to grow stack */
|
||||
|
||||
/* MIPS only supports 31 bits of virtual address space for user space */
|
||||
#define TARGET_RESERVED_VA 0x77000000
|
||||
|
||||
#define TARGET_VM_MINUSER_ADDRESS (0x00000000)
|
||||
#define TARGET_VM_MAXUSER_ADDRESS (0x80000000)
|
||||
|
||||
// #define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE)
|
||||
#define TARGET_USRSTACK (TARGET_RESERVED_VA - TARGET_PAGE_SIZE * 0x10)
|
||||
|
||||
static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
|
||||
{
|
||||
return state->active_tc.gpr[29];
|
||||
}
|
||||
|
||||
static inline void set_second_rval(CPUMIPSState *state, abi_ulong retval2)
|
||||
{
|
||||
state->active_tc.gpr[3] = retval2;
|
||||
}
|
||||
|
||||
#endif /* ! _TARGET_ARCH_VMPARAM_H_ */
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* mips64 specific prototypes for bsd-user
|
||||
*
|
||||
* 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 _TARGET_ARCH_H_
|
||||
#define _TARGET_ARCH_H_
|
||||
|
||||
#include "qemu.h"
|
||||
|
||||
void target_cpu_set_tls(CPUMIPSState *env, target_ulong newtls);
|
||||
target_ulong target_cpu_get_tls(CPUMIPSState *env);
|
||||
|
||||
#endif /* !_TARGET_ARCH_H_ */
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* mips64 cpu related code
|
||||
*
|
||||
* 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 "target_arch.h"
|
||||
|
||||
#define TP_OFFSET 0x7010
|
||||
|
||||
void target_cpu_set_tls(CPUMIPSState *env, target_ulong newtls)
|
||||
{
|
||||
env->active_tc.CP0_UserLocal = newtls + TP_OFFSET;
|
||||
}
|
||||
|
||||
target_ulong target_cpu_get_tls(CPUMIPSState *env)
|
||||
{
|
||||
return (env->active_tc.CP0_UserLocal - TP_OFFSET);
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* mips64 cpu init and loop
|
||||
*
|
||||
* 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 _TARGET_ARCH_CPU_H_
|
||||
#define _TARGET_ARCH_CPU_H_
|
||||
|
||||
#include "target_arch.h"
|
||||
|
||||
#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
|
||||
# define TARGET_DEFAULT_CPU_MODEL "MIPS64R2-generic"
|
||||
#else
|
||||
# define TARGET_DEFAULT_CPU_MODEL "24f"
|
||||
#endif
|
||||
|
||||
#define TARGET_CPU_RESET(cpu)
|
||||
|
||||
static inline void target_cpu_init(CPUMIPSState *env,
|
||||
struct target_pt_regs *regs)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
env->active_tc.gpr[i] = regs->regs[i];
|
||||
}
|
||||
env->active_tc.PC = regs->cp0_epc & ~(target_ulong)1;
|
||||
if (regs->cp0_epc & 1) {
|
||||
env->hflags |= MIPS_HFLAG_M16;
|
||||
}
|
||||
env->hflags |= MIPS_HFLAG_64;
|
||||
}
|
||||
|
||||
static inline void target_cpu_loop(CPUMIPSState *env)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
target_siginfo_t info;
|
||||
int trapnr;
|
||||
abi_long ret;
|
||||
unsigned int syscall_num;
|
||||
|
||||
for (;;) {
|
||||
cpu_exec_start(cs);
|
||||
trapnr = cpu_exec(cs);
|
||||
cpu_exec_end(cs);
|
||||
process_queued_cpu_work(cs);
|
||||
|
||||
switch (trapnr) {
|
||||
case EXCP_SYSCALL: /* syscall exception */
|
||||
if (bsd_type == target_freebsd) {
|
||||
syscall_num = env->active_tc.gpr[2]; /* v0 */
|
||||
env->active_tc.PC += TARGET_INSN_SIZE;
|
||||
if (syscall_num >= TARGET_FREEBSD_NR_MAXSYSCALL) {
|
||||
ret = -TARGET_ENOSYS;
|
||||
} else {
|
||||
/* mips64 uses regs 4-11 for args */
|
||||
if (TARGET_FREEBSD_NR___syscall == syscall_num ||
|
||||
TARGET_FREEBSD_NR_syscall == syscall_num) {
|
||||
/* indirect syscall */
|
||||
ret = do_freebsd_syscall(env,
|
||||
env->active_tc.gpr[4],/* syscall #*/
|
||||
env->active_tc.gpr[5], /* arg0 */
|
||||
env->active_tc.gpr[6], /* arg1 */
|
||||
env->active_tc.gpr[7], /* arg2 */
|
||||
env->active_tc.gpr[8], /* arg3 */
|
||||
env->active_tc.gpr[9], /* arg4 */
|
||||
env->active_tc.gpr[10],/* arg5 */
|
||||
env->active_tc.gpr[11],/* arg6 */
|
||||
0 /* no arg 7 */);
|
||||
} else {
|
||||
/* direct syscall */
|
||||
ret = do_freebsd_syscall(env,
|
||||
syscall_num,
|
||||
env->active_tc.gpr[4],
|
||||
env->active_tc.gpr[5],
|
||||
env->active_tc.gpr[6],
|
||||
env->active_tc.gpr[7],
|
||||
env->active_tc.gpr[8],
|
||||
env->active_tc.gpr[9],
|
||||
env->active_tc.gpr[10],
|
||||
env->active_tc.gpr[11]
|
||||
);
|
||||
}
|
||||
}
|
||||
/* Compare to mips/mips/vm_machdep.c cpu_set_syscall_retval() */
|
||||
if (-TARGET_EJUSTRETURN == ret) {
|
||||
/*
|
||||
* Returning from a successful sigreturn
|
||||
* syscall. Avoid clobbering register state.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
if (-TARGET_ERESTART == ret) {
|
||||
/* Backup the pc to point at the swi. */
|
||||
env->active_tc.PC -= TARGET_INSN_SIZE;
|
||||
break;
|
||||
}
|
||||
if ((unsigned int)ret >= (unsigned int)(-1133)) {
|
||||
env->active_tc.gpr[7] = 1;
|
||||
ret = -ret;
|
||||
} else {
|
||||
env->active_tc.gpr[7] = 0;
|
||||
}
|
||||
env->active_tc.gpr[2] = ret; /* v0 <- ret */
|
||||
} /* else if (bsd_type == target_openbsd)... */
|
||||
else {
|
||||
fprintf(stderr, "qemu: bsd_type (= %d) syscall not supported\n",
|
||||
bsd_type);
|
||||
}
|
||||
break;
|
||||
|
||||
case EXCP_TLBL: /* TLB miss on load */
|
||||
case EXCP_TLBS: /* TLB miss on store */
|
||||
case EXCP_AdEL: /* bad address on load */
|
||||
case EXCP_AdES: /* bad address on store */
|
||||
info.target_si_signo = TARGET_SIGSEGV;
|
||||
info.target_si_errno = 0;
|
||||
/* XXX: check env->error_code */
|
||||
info.target_si_code = TARGET_SEGV_MAPERR;
|
||||
info.target_si_addr = env->CP0_BadVAddr;
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
break;
|
||||
|
||||
case EXCP_CpU: /* coprocessor unusable */
|
||||
case EXCP_RI: /* reserved instruction */
|
||||
info.target_si_signo = TARGET_SIGILL;
|
||||
info.target_si_errno = 0;
|
||||
info.target_si_code = 0;
|
||||
queue_signal(env, info.target_si_signo, &info);
|
||||
break;
|
||||
|
||||
case EXCP_INTERRUPT: /* async interrupt */
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
|
||||
case EXCP_DEBUG: /* cpu stopped after a breakpoint */
|
||||
{
|
||||
|
||||
info.target_si_signo = TARGET_SIGTRAP;
|
||||
info.target_si_errno = 0;
|
||||
info.target_si_code = TARGET_TRAP_BRKPT;
|
||||
queue_signal(env, info.target_si_signo, &info);
|
||||
}
|
||||
break;
|
||||
|
||||
case EXCP_ATOMIC:
|
||||
cpu_exec_step_atomic(cs);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "qemu: unhandled CPU exception "
|
||||
"0x%x - aborting\n", trapnr);
|
||||
cpu_dump_state(cs, stderr, 0);
|
||||
abort();
|
||||
}
|
||||
process_pending_signals(env);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void target_cpu_clone_regs(CPUMIPSState *env, target_ulong newsp)
|
||||
{
|
||||
if (newsp)
|
||||
env->active_tc.gpr[29] = newsp;
|
||||
env->active_tc.gpr[7] = 0;
|
||||
env->active_tc.gpr[2] = 0;
|
||||
}
|
||||
|
||||
static inline void target_cpu_reset(CPUArchState *cpu)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* ! _TARGET_ARCH_CPU_H_ */
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* mips64 ELF 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 _TARGET_ARCH_ELF_H_
|
||||
#define _TARGET_ARCH_ELF_H_
|
||||
|
||||
#define elf_check_arch(x) ( (x) == EM_MIPS )
|
||||
#define ELF_START_MMAP 0x2aaaaab000ULL
|
||||
#define ELF_ET_DYN_LOAD_ADDR 0x0120000
|
||||
#define ELF_CLASS ELFCLASS64
|
||||
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
#define ELF_DATA ELFDATA2MSB
|
||||
#else
|
||||
#define ELF_DATA ELFDATA2LSB
|
||||
#endif
|
||||
#define ELF_ARCH EM_MIPS
|
||||
|
||||
#define USE_ELF_CORE_DUMP
|
||||
#define ELF_EXEC_PAGESIZE 4096
|
||||
|
||||
#endif /* _TARGET_ARCH_ELF_H_ */
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* FreeBSD mips64 register structures
|
||||
*
|
||||
* Copyright (c) 2015 Stacey Son
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 _TARGET_ARCH_REG_H_
|
||||
#define _TARGET_ARCH_REG_H_
|
||||
|
||||
/* See sys/mips64/include/reg.h */
|
||||
#define TARGET_NUMSAVEREGS 40
|
||||
typedef struct target_reg {
|
||||
uint64_t r_regs[TARGET_NUMSAVEREGS];
|
||||
} target_reg_t;
|
||||
|
||||
#define TARGET_NUMFPREGS 34
|
||||
typedef struct target_fpreg {
|
||||
uint64_t r_regs[TARGET_NUMFPREGS];
|
||||
} target_fpreg_t;
|
||||
|
||||
#define tswapreg(ptr) tswapal(ptr)
|
||||
|
||||
static inline void target_copy_regs(target_reg_t *regs, const CPUMIPSState *env)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* See sys/mips/include/frame.h struct trapframe or
|
||||
* sys/mips/include/regnum.h for register order.
|
||||
*/
|
||||
for (i = 0; i < 32; i++)
|
||||
regs->r_regs[i] = tswapreg(env->active_tc.gpr[i]);
|
||||
regs->r_regs[32] = tswapreg(env->CP0_Status); /* sr */
|
||||
regs->r_regs[33] = tswapreg(env->active_tc.LO[0]); /* mullo */
|
||||
regs->r_regs[34] = tswapreg(env->active_tc.HI[0]); /* mulhi */
|
||||
regs->r_regs[35] = tswapreg(env->CP0_BadVAddr);
|
||||
regs->r_regs[36] = tswapreg(env->CP0_Cause);
|
||||
regs->r_regs[37] = tswapreg(env->active_tc.PC);
|
||||
regs->r_regs[38] = 0; /* ic (RM7k and RM9k specific) */
|
||||
regs->r_regs[39] = 0; /* Dummy for 8 byte alignment */
|
||||
}
|
||||
|
||||
#undef tswapreg
|
||||
|
||||
#endif /* !_TARGET_ARCH_REG_H_ */
|
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
* mips64 signal definitions
|
||||
*
|
||||
*
|
||||
* 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 _TARGET_ARCH_SIGNAL_H_
|
||||
#define _TARGET_ARCH_SIGNAL_H_
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
#define TARGET_INSN_SIZE 4 /* mips64 instruction size */
|
||||
|
||||
/* Size of the signal trampolin code placed on the stack. */
|
||||
#define TARGET_SZSIGCODE ((abi_ulong)(4 * TARGET_INSN_SIZE))
|
||||
|
||||
#define TARGET_MINSIGSTKSZ (512 * 4)
|
||||
#define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768)
|
||||
|
||||
/* compare to sys/mips/include/asm.h */
|
||||
#define TARGET_SZREG 8
|
||||
#define TARGET_CALLFRAME_SIZ (TARGET_SZREG * 4)
|
||||
|
||||
/* mips/mips/pm_machdep.c */
|
||||
#define TARGET_UCONTEXT_MAGIC 0xACEDBADE
|
||||
#define TARGET_MC_GET_CLEAR_RET 0x0001
|
||||
#define TARGET_MC_ADD_MAGIC 0x0002
|
||||
#define TARGET_MC_SET_ONSTACK 0x0004
|
||||
|
||||
struct target_sigcontext {
|
||||
target_sigset_t sc_mask; /* signal mask to retstore */
|
||||
int32_t sc_onstack; /* sigstack state to restore */
|
||||
abi_long sc_pc; /* pc at time of signal */
|
||||
abi_long sc_reg[32]; /* processor regs 0 to 31 */
|
||||
abi_long mullo, mulhi; /* mullo and mulhi registers */
|
||||
int32_t sc_fpused; /* fp has been used */
|
||||
abi_long sc_fpregs[33]; /* fp regs 0 to 31 & csr */
|
||||
abi_long sc_fpc_eir; /* fp exception instr reg */
|
||||
/* int32_t reserved[8]; */
|
||||
};
|
||||
|
||||
typedef struct target_mcontext {
|
||||
int32_t mc_onstack; /* sigstack state to restore */
|
||||
abi_long mc_pc; /* pc at time of signal */
|
||||
abi_long mc_regs[32]; /* process regs 0 to 31 */
|
||||
abi_long sr; /* status register */
|
||||
abi_long mullo, mulhi;
|
||||
int32_t mc_fpused; /* fp has been used */
|
||||
abi_long mc_fpregs[33]; /* fp regs 0 to 32 & csr */
|
||||
abi_long mc_fpc_eir; /* fp exception instr reg */
|
||||
abi_ulong mc_tls; /* pointer to TLS area */
|
||||
} target_mcontext_t;
|
||||
|
||||
typedef struct target_ucontext {
|
||||
target_sigset_t uc_sigmask;
|
||||
target_mcontext_t uc_mcontext;
|
||||
abi_ulong uc_link;
|
||||
target_stack_t uc_stack;
|
||||
int32_t uc_flags;
|
||||
int32_t __spare__[4];
|
||||
} target_ucontext_t;
|
||||
|
||||
struct target_sigframe {
|
||||
abi_ulong sf_signum;
|
||||
abi_ulong sf_siginfo; /* code or pointer to sf_si */
|
||||
abi_ulong sf_ucontext; /* points to sf_uc */
|
||||
abi_ulong sf_addr; /* undocumented 4th arg */
|
||||
target_ucontext_t sf_uc; /* = *sf_uncontext */
|
||||
target_siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
|
||||
uint32_t __spare__[2];
|
||||
};
|
||||
|
||||
/* Forward declare due to unfortunate header nesting */
|
||||
void target_cpu_set_tls(CPUMIPSState *env, target_ulong newtls);
|
||||
target_ulong target_cpu_get_tls(CPUMIPSState *env);
|
||||
|
||||
/*
|
||||
* Compare to mips/mips/pm_machdep.c sendsig()
|
||||
* Assumes that target stack frame memory is locked.
|
||||
*/
|
||||
static inline abi_long
|
||||
set_sigtramp_args(CPUMIPSState *regs, int sig, struct target_sigframe *frame,
|
||||
abi_ulong frame_addr, struct target_sigaction *ka)
|
||||
{
|
||||
|
||||
/* frame->sf_si.si_addr = regs->CP0_BadVAddr; */
|
||||
|
||||
/* MIPS only struct target_sigframe members: */
|
||||
frame->sf_signum = sig;
|
||||
frame->sf_siginfo = frame_addr + offsetof(struct target_sigframe, sf_si);
|
||||
frame->sf_ucontext = frame_addr + offsetof(struct target_sigframe, sf_uc);
|
||||
|
||||
/*
|
||||
* Arguments to signal handler:
|
||||
* a0 ($4) = signal number
|
||||
* a1 ($5) = siginfo pointer
|
||||
* a2 ($6) = ucontext pointer
|
||||
* PC = signal handler pointer
|
||||
* t9 ($25) = signal handler pointer
|
||||
* $29 = point to sigframe struct
|
||||
* ra ($31) = sigtramp at base of user stack
|
||||
*/
|
||||
regs->active_tc.gpr[4] = sig;
|
||||
regs->active_tc.gpr[5] = frame_addr +
|
||||
offsetof(struct target_sigframe, sf_si);
|
||||
regs->active_tc.gpr[6] = frame_addr +
|
||||
offsetof(struct target_sigframe, sf_uc);
|
||||
regs->active_tc.gpr[25] = regs->active_tc.PC = ka->_sa_handler;
|
||||
regs->active_tc.gpr[29] = frame_addr;
|
||||
regs->active_tc.gpr[31] = TARGET_PS_STRINGS - TARGET_SZSIGCODE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare to mips/mips/pm_machdep.c get_mcontext()
|
||||
* Assumes that the memory is locked if mcp points to user memory.
|
||||
*/
|
||||
static inline abi_long get_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp,
|
||||
int flags)
|
||||
{
|
||||
int i, err = 0;
|
||||
|
||||
if (flags & TARGET_MC_ADD_MAGIC) {
|
||||
mcp->mc_regs[0] = tswapal(TARGET_UCONTEXT_MAGIC);
|
||||
} else {
|
||||
mcp->mc_regs[0] = 0;
|
||||
}
|
||||
|
||||
if (flags & TARGET_MC_SET_ONSTACK) {
|
||||
mcp->mc_onstack = tswapal(1);
|
||||
} else {
|
||||
mcp->mc_onstack = 0;
|
||||
}
|
||||
|
||||
for (i = 1; i < 32; i++) {
|
||||
mcp->mc_regs[i] = tswapal(regs->active_tc.gpr[i]);
|
||||
}
|
||||
|
||||
mcp->mc_fpused = 1;
|
||||
for (i = 0; i < 32; i++) {
|
||||
mcp->mc_fpregs[i] = tswapal(regs->active_fpu.fpr[i].d);
|
||||
}
|
||||
mcp->mc_fpregs[32] = tswapal(regs->active_fpu.fcr0);
|
||||
mcp->mc_fpc_eir = tswapal(regs->active_fpu.fcr31);
|
||||
|
||||
if (flags & TARGET_MC_GET_CLEAR_RET) {
|
||||
mcp->mc_regs[2] = 0; /* v0 = 0 */
|
||||
mcp->mc_regs[3] = 0; /* v1 = 0 */
|
||||
mcp->mc_regs[7] = 0; /* a3 = 0 */
|
||||
}
|
||||
|
||||
mcp->mc_pc = tswapal(regs->active_tc.PC);
|
||||
mcp->mullo = tswapal(regs->active_tc.LO[0]);
|
||||
mcp->mulhi = tswapal(regs->active_tc.HI[0]);
|
||||
mcp->mc_tls = tswapal(target_cpu_get_tls(regs));
|
||||
|
||||
/* Don't do any of the status and cause registers. */
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Compare to mips/mips/pm_machdep.c set_mcontext() */
|
||||
static inline abi_long set_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp,
|
||||
int srflag)
|
||||
{
|
||||
int i, err = 0;
|
||||
|
||||
for (i = 1; i < 32; i++) {
|
||||
regs->active_tc.gpr[i] = tswapal(mcp->mc_regs[i]);
|
||||
}
|
||||
|
||||
if (mcp->mc_fpused) {
|
||||
/* restore fpu context if we have used it before */
|
||||
for (i = 0; i < 32; i++) {
|
||||
regs->active_fpu.fpr[i].d = tswapal(mcp->mc_fpregs[i]);
|
||||
}
|
||||
regs->active_fpu.fcr0 = tswapal(mcp->mc_fpregs[32]);
|
||||
regs->active_fpu.fcr31 = tswapal(mcp->mc_fpc_eir);
|
||||
}
|
||||
|
||||
regs->CP0_EPC = tswapal(mcp->mc_pc);
|
||||
regs->active_tc.LO[0] = tswapal(mcp->mullo);
|
||||
regs->active_tc.HI[0] = tswapal(mcp->mulhi);
|
||||
target_cpu_set_tls(regs, tswapal(mcp->mc_tls));
|
||||
|
||||
if (srflag) {
|
||||
/* doing sigreturn() */
|
||||
regs->active_tc.PC = regs->CP0_EPC;
|
||||
regs->CP0_EPC = 0; /* XXX for nested signals ? */
|
||||
}
|
||||
|
||||
/* Don't do any of the status and cause registers. */
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline abi_long get_ucontext_sigreturn(CPUMIPSState *regs,
|
||||
abi_ulong target_sf, abi_ulong *target_uc)
|
||||
{
|
||||
|
||||
/* mips passes ucontext struct as the stack frame */
|
||||
*target_uc = target_sf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* !_TARGET_ARCH_SIGNAL_H_ */
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
#ifndef _TARGET_ARCH_SIGTRAMP_H_
|
||||
#define _TARGET_ARCH_SIGTRAMP_H_
|
||||
|
||||
/* Compare to mips/mips/locore.S sigcode() */
|
||||
static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
|
||||
unsigned sys_sigreturn)
|
||||
{
|
||||
int i;
|
||||
uint32_t sigtramp_code[TARGET_SZSIGCODE/TARGET_INSN_SIZE] = {
|
||||
/* 1 */ 0x67A40000 + sigf_uc, /* daddu $a0, $sp, (sigf_uc) */
|
||||
/* 2 */ 0x24020000 + sys_sigreturn, /* li $v0, (sys_sigreturn) */
|
||||
/* 3 */ 0x0000000C, /* syscall */
|
||||
/* 4 */ 0x0000000D /* break */
|
||||
};
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
tswap32s(&sigtramp_code[i]);
|
||||
}
|
||||
|
||||
return memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE);
|
||||
}
|
||||
#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue