mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-06 01:03:55 -06:00
better signal/exception support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@42 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
66fb9763af
commit
9de5e440b9
15 changed files with 644 additions and 208 deletions
|
@ -261,6 +261,9 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
|
|||
/* Create enough stack to hold everything. If we don't use
|
||||
* it for args, we'll use it for something else...
|
||||
*/
|
||||
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
|
||||
we allocate a bigger stack. Need a better solution, for example
|
||||
by remapping the process stack directly at the right place */
|
||||
if(x86_stack_size > MAX_ARG_PAGES*X86_PAGE_SIZE) {
|
||||
if((long)mmap4k((void *)(X86_STACK_TOP-x86_stack_size), x86_stack_size + X86_PAGE_SIZE,
|
||||
PROT_READ | PROT_WRITE,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* emulated ioctl list */
|
||||
|
||||
IOCTL(TCGETS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
|
||||
IOCTL(TCGETS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
|
||||
IOCTL(TCSETS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
|
||||
IOCTL(TCSETSF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
|
||||
IOCTL(TCSETSW, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
|
||||
IOCTL(TIOCGWINSZ, IOC_R, MK_PTR(MK_STRUCT(STRUCT_winsize)))
|
||||
|
@ -199,8 +199,12 @@
|
|||
IOCTL(SNDCTL_TMR_METRONOME, IOC_W, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_TMR_SELECT, IOC_W, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_TMR_SOURCE, IOC_RW, MK_PTR(TYPE_INT))
|
||||
#if 0
|
||||
/* we invalidate these defines because they have a same number as
|
||||
termios ioctls */
|
||||
IOCTL(SNDCTL_TMR_START, 0, TYPE_NULL)
|
||||
IOCTL(SNDCTL_TMR_STOP, 0, TYPE_NULL)
|
||||
#endif
|
||||
IOCTL(SNDCTL_TMR_TEMPO, IOC_RW, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_TMR_TIMEBASE, IOC_RW, MK_PTR(TYPE_INT))
|
||||
|
||||
|
|
|
@ -33,7 +33,10 @@
|
|||
FILE *logfile = NULL;
|
||||
int loglevel;
|
||||
|
||||
unsigned long x86_stack_size;
|
||||
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
|
||||
we allocate a bigger stack. Need a better solution, for example
|
||||
by remapping the process stack directly at the right place */
|
||||
unsigned long x86_stack_size = 512 * 1024;
|
||||
unsigned long stktop;
|
||||
|
||||
void gemu_log(const char *fmt, ...)
|
||||
|
@ -102,10 +105,11 @@ uint64_t gdt_table[6];
|
|||
|
||||
void cpu_loop(struct CPUX86State *env)
|
||||
{
|
||||
int err;
|
||||
uint8_t *pc;
|
||||
target_siginfo_t info;
|
||||
|
||||
for(;;) {
|
||||
int err;
|
||||
uint8_t *pc;
|
||||
|
||||
err = cpu_x86_exec(env);
|
||||
pc = env->seg_cache[R_CS].base + env->eip;
|
||||
switch(err) {
|
||||
|
@ -122,12 +126,42 @@ void cpu_loop(struct CPUX86State *env)
|
|||
env->regs[R_EDI],
|
||||
env->regs[R_EBP]);
|
||||
} else {
|
||||
goto trap_error;
|
||||
/* XXX: more precise info */
|
||||
info.si_signo = SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
info.si_code = 0;
|
||||
info._sifields._sigfault._addr = 0;
|
||||
queue_signal(info.si_signo, &info);
|
||||
}
|
||||
break;
|
||||
case EXCP00_DIVZ:
|
||||
/* division by zero */
|
||||
info.si_signo = SIGFPE;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_FPE_INTDIV;
|
||||
info._sifields._sigfault._addr = env->eip;
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP04_INTO:
|
||||
case EXCP05_BOUND:
|
||||
info.si_signo = SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
info.si_code = 0;
|
||||
info._sifields._sigfault._addr = 0;
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP06_ILLOP:
|
||||
info.si_signo = SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_ILLOPN;
|
||||
info._sifields._sigfault._addr = env->eip;
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP_INTERRUPT:
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
default:
|
||||
trap_error:
|
||||
fprintf(stderr, "0x%08lx: Unknown exception %d, aborting\n",
|
||||
fprintf(stderr, "0x%08lx: Unknown exception CPU %d, aborting\n",
|
||||
(long)pc, err);
|
||||
abort();
|
||||
}
|
||||
|
@ -144,6 +178,9 @@ void usage(void)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
/* XXX: currently only used for async signals (see signal.c) */
|
||||
CPUX86State *global_env;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *filename;
|
||||
|
@ -199,6 +236,7 @@ int main(int argc, char **argv)
|
|||
signal_init();
|
||||
|
||||
env = cpu_x86_init();
|
||||
global_env = env;
|
||||
|
||||
/* linux register setup */
|
||||
env->regs[R_EAX] = regs->eax;
|
||||
|
|
|
@ -3,30 +3,12 @@
|
|||
|
||||
#include "thunk.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include "syscall_defs.h"
|
||||
|
||||
#ifdef TARGET_I386
|
||||
|
||||
/* default linux values for the selectors */
|
||||
#define __USER_CS (0x23)
|
||||
#define __USER_DS (0x2B)
|
||||
|
||||
struct target_pt_regs {
|
||||
long ebx;
|
||||
long ecx;
|
||||
long edx;
|
||||
long esi;
|
||||
long edi;
|
||||
long ebp;
|
||||
long eax;
|
||||
int xds;
|
||||
int xes;
|
||||
long orig_eax;
|
||||
long eip;
|
||||
int xcs;
|
||||
long eflags;
|
||||
long esp;
|
||||
int xss;
|
||||
};
|
||||
|
||||
#include "cpu-i386.h"
|
||||
#include "syscall-i386.h"
|
||||
#endif
|
||||
|
||||
/* This struct is used to hold certain information about the image.
|
||||
|
@ -59,9 +41,10 @@ void syscall_init(void);
|
|||
long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
long arg4, long arg5, long arg6);
|
||||
void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
|
||||
struct CPUX86State;
|
||||
void cpu_loop(struct CPUX86State *env);
|
||||
extern CPUX86State *global_env;
|
||||
void cpu_loop(CPUX86State *env);
|
||||
void process_pending_signals(void *cpu_env);
|
||||
void signal_init(void);
|
||||
int queue_signal(int sig, target_siginfo_t *info);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -27,13 +27,6 @@
|
|||
|
||||
#include "gemu.h"
|
||||
|
||||
#include "syscall_defs.h"
|
||||
|
||||
#ifdef TARGET_I386
|
||||
#include "cpu-i386.h"
|
||||
#include "syscall-i386.h"
|
||||
#endif
|
||||
|
||||
/* signal handling inspired from em86. */
|
||||
|
||||
//#define DEBUG_SIGNAL
|
||||
|
@ -42,7 +35,7 @@
|
|||
|
||||
struct sigqueue {
|
||||
struct sigqueue *next;
|
||||
siginfo_t info;
|
||||
target_siginfo_t info;
|
||||
};
|
||||
|
||||
struct emulated_sigaction {
|
||||
|
@ -101,20 +94,66 @@ void target_to_host_old_sigset(sigset_t *sigset,
|
|||
*(unsigned long *)sigset = tswapl(*old_sigset);
|
||||
}
|
||||
|
||||
/* XXX: finish it */
|
||||
void host_to_target_siginfo(target_siginfo_t *tinfo, siginfo_t *info)
|
||||
/* siginfo conversion */
|
||||
|
||||
static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
|
||||
const siginfo_t *info)
|
||||
{
|
||||
tinfo->si_signo = tswap32(info->si_signo);
|
||||
tinfo->si_errno = tswap32(info->si_errno);
|
||||
tinfo->si_code = tswap32(info->si_code);
|
||||
int sig;
|
||||
sig = host_to_target_signal(info->si_signo);
|
||||
tinfo->si_signo = sig;
|
||||
tinfo->si_errno = 0;
|
||||
tinfo->si_code = 0;
|
||||
if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS) {
|
||||
/* should never come here, but who knows. The information for
|
||||
the target is irrelevant */
|
||||
tinfo->_sifields._sigfault._addr = 0;
|
||||
} else if (sig >= TARGET_SIGRTMIN) {
|
||||
tinfo->_sifields._rt._pid = info->si_pid;
|
||||
tinfo->_sifields._rt._uid = info->si_uid;
|
||||
/* XXX: potential problem if 64 bit */
|
||||
tinfo->_sifields._rt._sigval.sival_ptr =
|
||||
(target_ulong)info->si_value.sival_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX: finish it */
|
||||
void target_to_host_siginfo(siginfo_t *info, target_siginfo_t *tinfo)
|
||||
static void tswap_siginfo(target_siginfo_t *tinfo,
|
||||
const target_siginfo_t *info)
|
||||
{
|
||||
int sig;
|
||||
sig = info->si_signo;
|
||||
tinfo->si_signo = tswap32(sig);
|
||||
tinfo->si_errno = tswap32(info->si_errno);
|
||||
tinfo->si_code = tswap32(info->si_code);
|
||||
if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS) {
|
||||
tinfo->_sifields._sigfault._addr =
|
||||
tswapl(info->_sifields._sigfault._addr);
|
||||
} else if (sig >= TARGET_SIGRTMIN) {
|
||||
tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
|
||||
tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
|
||||
tinfo->_sifields._rt._sigval.sival_ptr =
|
||||
tswapl(info->_sifields._rt._sigval.sival_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
|
||||
{
|
||||
host_to_target_siginfo_noswap(tinfo, info);
|
||||
tswap_siginfo(tinfo, tinfo);
|
||||
}
|
||||
|
||||
/* XXX: we support only POSIX RT signals are used. */
|
||||
/* XXX: find a solution for 64 bit (additionnal malloced data is needed) */
|
||||
void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
|
||||
{
|
||||
info->si_signo = tswap32(tinfo->si_signo);
|
||||
info->si_errno = tswap32(tinfo->si_errno);
|
||||
info->si_code = tswap32(tinfo->si_code);
|
||||
info->si_pid = tswap32(tinfo->_sifields._rt._pid);
|
||||
info->si_uid = tswap32(tinfo->_sifields._rt._uid);
|
||||
info->si_value.sival_ptr =
|
||||
(void *)tswapl(tinfo->_sifields._rt._sigval.sival_ptr);
|
||||
}
|
||||
|
||||
void signal_init(void)
|
||||
|
@ -122,8 +161,9 @@ void signal_init(void)
|
|||
struct sigaction act;
|
||||
int i;
|
||||
|
||||
/* set all host signal handlers */
|
||||
sigemptyset(&act.sa_mask);
|
||||
/* set all host signal handlers. ALL signals are blocked during
|
||||
the handlers to serialize them. */
|
||||
sigfillset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
act.sa_sigaction = host_signal_handler;
|
||||
for(i = 1; i < NSIG; i++) {
|
||||
|
@ -155,56 +195,40 @@ static inline void free_sigqueue(struct sigqueue *q)
|
|||
first_free = q;
|
||||
}
|
||||
|
||||
static int queue_signal(struct emulated_sigaction *k, int sig, siginfo_t *info)
|
||||
{
|
||||
struct sigqueue *q, **pq;
|
||||
|
||||
pq = &k->first;
|
||||
if (!k->pending || sig < TARGET_SIGRTMIN) {
|
||||
/* first signal or non real time signal */
|
||||
q = &k->info;
|
||||
} else {
|
||||
q = alloc_sigqueue();
|
||||
if (!q)
|
||||
return -EAGAIN;
|
||||
while (*pq != NULL)
|
||||
pq = &(*pq)->next;
|
||||
}
|
||||
*pq = q;
|
||||
q->info = *info;
|
||||
q->next = NULL;
|
||||
k->pending = 1;
|
||||
/* signal that a new signal is pending */
|
||||
signal_pending = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void force_sig(int sig)
|
||||
/* abort execution with signal */
|
||||
void __attribute((noreturn)) force_sig(int sig)
|
||||
{
|
||||
int host_sig;
|
||||
/* abort execution with signal */
|
||||
host_sig = target_to_host_signal(sig);
|
||||
fprintf(stderr, "gemu: uncaught target signal %d (%s) - exiting\n",
|
||||
sig, strsignal(host_sig));
|
||||
#if 1
|
||||
_exit(-host_sig);
|
||||
#else
|
||||
{
|
||||
struct sigaction act;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
act.sa_sigaction = SIG_DFL;
|
||||
sigaction(SIGABRT, &act, NULL);
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void host_signal_handler(int host_signum, siginfo_t *info,
|
||||
void *puc)
|
||||
/* queue a signal so that it will be send to the virtual CPU as soon
|
||||
as possible */
|
||||
int queue_signal(int sig, target_siginfo_t *info)
|
||||
{
|
||||
struct emulated_sigaction *k;
|
||||
int sig;
|
||||
struct sigqueue *q, **pq;
|
||||
target_ulong handler;
|
||||
|
||||
/* get target signal number */
|
||||
sig = host_to_target_signal(host_signum);
|
||||
if (sig < 1 || sig > TARGET_NSIG)
|
||||
return;
|
||||
k = &sigact_table[sig - 1];
|
||||
#ifdef DEBUG_SIGNAL
|
||||
fprintf(stderr, "gemu: got signal %d\n", sig);
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
fprintf(stderr, "queue_sigal: sig=%d\n",
|
||||
sig);
|
||||
#endif
|
||||
k = &sigact_table[sig - 1];
|
||||
handler = k->sa._sa_handler;
|
||||
if (handler == TARGET_SIG_DFL) {
|
||||
/* default handler : ignore some signal. The other are fatal */
|
||||
|
@ -212,13 +236,96 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
|
|||
sig != TARGET_SIGURG &&
|
||||
sig != TARGET_SIGWINCH) {
|
||||
force_sig(sig);
|
||||
} else {
|
||||
return 0; /* indicate ignored */
|
||||
}
|
||||
} else if (handler == TARGET_SIG_IGN) {
|
||||
/* ignore signal */
|
||||
return 0;
|
||||
} else if (handler == TARGET_SIG_ERR) {
|
||||
force_sig(sig);
|
||||
} else {
|
||||
queue_signal(k, sig, info);
|
||||
pq = &k->first;
|
||||
if (sig < TARGET_SIGRTMIN) {
|
||||
/* if non real time signal, we queue exactly one signal */
|
||||
if (!k->pending)
|
||||
q = &k->info;
|
||||
else
|
||||
return 0;
|
||||
} else {
|
||||
if (!k->pending) {
|
||||
/* first signal */
|
||||
q = &k->info;
|
||||
} else {
|
||||
q = alloc_sigqueue();
|
||||
if (!q)
|
||||
return -EAGAIN;
|
||||
while (*pq != NULL)
|
||||
pq = &(*pq)->next;
|
||||
}
|
||||
}
|
||||
*pq = q;
|
||||
q->info = *info;
|
||||
q->next = NULL;
|
||||
k->pending = 1;
|
||||
/* signal that a new signal is pending */
|
||||
signal_pending = 1;
|
||||
return 1; /* indicates that the signal was queued */
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
#ifdef __i386__
|
||||
static void dump_regs(struct ucontext *uc)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
|
||||
"ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
|
||||
"EFL=%08x EIP=%08x\n",
|
||||
uc->uc_mcontext.gregs[EAX],
|
||||
uc->uc_mcontext.gregs[EBX],
|
||||
uc->uc_mcontext.gregs[ECX],
|
||||
uc->uc_mcontext.gregs[EDX],
|
||||
uc->uc_mcontext.gregs[ESI],
|
||||
uc->uc_mcontext.gregs[EDI],
|
||||
uc->uc_mcontext.gregs[EBP],
|
||||
uc->uc_mcontext.gregs[ESP],
|
||||
uc->uc_mcontext.gregs[EFL],
|
||||
uc->uc_mcontext.gregs[EIP]);
|
||||
}
|
||||
#else
|
||||
static void dump_regs(struct ucontext *uc)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
static void host_signal_handler(int host_signum, siginfo_t *info,
|
||||
void *puc)
|
||||
{
|
||||
int sig;
|
||||
target_siginfo_t tinfo;
|
||||
|
||||
/* the CPU emulator uses some host signals to detect exceptions,
|
||||
we we forward to it some signals */
|
||||
if (host_signum == SIGSEGV || host_signum == SIGBUS) {
|
||||
if (cpu_x86_signal_handler(host_signum, info, puc))
|
||||
return;
|
||||
}
|
||||
|
||||
/* get target signal number */
|
||||
sig = host_to_target_signal(host_signum);
|
||||
if (sig < 1 || sig > TARGET_NSIG)
|
||||
return;
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
fprintf(stderr, "gemu: got signal %d\n", sig);
|
||||
dump_regs(puc);
|
||||
#endif
|
||||
host_to_target_siginfo_noswap(&tinfo, info);
|
||||
if (queue_signal(sig, &tinfo) == 1) {
|
||||
/* interrupt the virtual CPU as soon as possible */
|
||||
cpu_x86_interrupt(global_env);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -388,9 +495,10 @@ struct rt_sigframe
|
|||
0;\
|
||||
})
|
||||
|
||||
static inline int copy_siginfo_to_user(target_siginfo_t *tinfo, siginfo_t *info)
|
||||
static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
|
||||
const target_siginfo_t *info)
|
||||
{
|
||||
host_to_target_siginfo(tinfo, info);
|
||||
tswap_siginfo(tinfo, info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -531,7 +639,8 @@ give_sigsegv:
|
|||
force_sig(TARGET_SIGSEGV /* , current */);
|
||||
}
|
||||
|
||||
static void setup_rt_frame(int sig, struct emulated_sigaction *ka, siginfo_t *info,
|
||||
static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
|
||||
target_siginfo_t *info,
|
||||
target_sigset_t *set, CPUX86State *env)
|
||||
{
|
||||
struct rt_sigframe *frame;
|
||||
|
@ -734,7 +843,8 @@ void process_pending_signals(void *cpu_env)
|
|||
{
|
||||
int sig;
|
||||
target_ulong handler;
|
||||
target_sigset_t set;
|
||||
sigset_t set, old_set;
|
||||
target_sigset_t target_old_set;
|
||||
struct emulated_sigaction *k;
|
||||
struct sigqueue *q;
|
||||
|
||||
|
@ -774,12 +884,24 @@ void process_pending_signals(void *cpu_env)
|
|||
} else if (handler == TARGET_SIG_ERR) {
|
||||
force_sig(sig);
|
||||
} else {
|
||||
set = k->sa.sa_mask;
|
||||
/* send the signal to the CPU */
|
||||
/* compute the blocked signals during the handler execution */
|
||||
target_to_host_sigset(&set, &k->sa.sa_mask);
|
||||
/* SA_NODEFER indicates that the current signal should not be
|
||||
blocked during the handler */
|
||||
if (!(k->sa.sa_flags & TARGET_SA_NODEFER))
|
||||
sigaddset(&set, target_to_host_signal(sig));
|
||||
|
||||
/* block signals in the handler using Linux */
|
||||
sigprocmask(SIG_BLOCK, &set, &old_set);
|
||||
/* save the previous blocked signal state to restore it at the
|
||||
end of the signal execution (see do_sigreturn) */
|
||||
host_to_target_sigset(&target_old_set, &old_set);
|
||||
|
||||
/* prepare the stack frame of the virtual CPU */
|
||||
if (k->sa.sa_flags & TARGET_SA_SIGINFO)
|
||||
setup_rt_frame(sig, k, &q->info, &set, cpu_env);
|
||||
setup_rt_frame(sig, k, &q->info, &target_old_set, cpu_env);
|
||||
else
|
||||
setup_frame(sig, k, &set, cpu_env);
|
||||
setup_frame(sig, k, &target_old_set, cpu_env);
|
||||
if (k->sa.sa_flags & TARGET_SA_RESETHAND)
|
||||
k->sa._sa_handler = TARGET_SIG_DFL;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include <sched.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/poll.h>
|
||||
//#include <sys/user.h>
|
||||
|
||||
#define termios host_termios
|
||||
|
@ -68,15 +69,8 @@
|
|||
#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])
|
||||
#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2])
|
||||
|
||||
#include "syscall_defs.h"
|
||||
|
||||
#ifdef TARGET_I386
|
||||
#include "cpu-i386.h"
|
||||
#include "syscall-i386.h"
|
||||
#endif
|
||||
|
||||
void host_to_target_siginfo(target_siginfo_t *tinfo, siginfo_t *info);
|
||||
void target_to_host_siginfo(siginfo_t *info, target_siginfo_t *tinfo);
|
||||
void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
|
||||
void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
|
||||
long do_sigreturn(CPUX86State *env);
|
||||
long do_rt_sigreturn(CPUX86State *env);
|
||||
|
||||
|
@ -106,6 +100,9 @@ _syscall2(int,sys_fstatfs,int,fd,struct kernel_statfs *,buf)
|
|||
_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
|
||||
|
||||
extern int personality(int);
|
||||
extern int flock(int, int);
|
||||
extern int setfsuid(int);
|
||||
extern int setfsgid(int);
|
||||
|
||||
static inline long get_errno(long ret)
|
||||
{
|
||||
|
@ -437,7 +434,7 @@ static long do_ioctl(long fd, long cmd, long arg)
|
|||
ie++;
|
||||
}
|
||||
arg_type = ie->arg_type;
|
||||
#ifdef DEBUG
|
||||
#if defined(DEBUG)
|
||||
gemu_log("ioctl: cmd=0x%04lx (%s)\n", cmd, ie->name);
|
||||
#endif
|
||||
switch(arg_type[0]) {
|
||||
|
@ -1244,9 +1241,30 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||
ret = get_errno(sethostname((const char *)arg1, arg2));
|
||||
break;
|
||||
case TARGET_NR_setrlimit:
|
||||
goto unimplemented;
|
||||
{
|
||||
/* XXX: convert resource ? */
|
||||
int resource = arg1;
|
||||
struct target_rlimit *target_rlim = (void *)arg2;
|
||||
struct rlimit rlim;
|
||||
rlim.rlim_cur = tswapl(target_rlim->rlim_cur);
|
||||
rlim.rlim_max = tswapl(target_rlim->rlim_max);
|
||||
ret = get_errno(setrlimit(resource, &rlim));
|
||||
}
|
||||
break;
|
||||
case TARGET_NR_getrlimit:
|
||||
goto unimplemented;
|
||||
{
|
||||
/* XXX: convert resource ? */
|
||||
int resource = arg1;
|
||||
struct target_rlimit *target_rlim = (void *)arg2;
|
||||
struct rlimit rlim;
|
||||
|
||||
ret = get_errno(getrlimit(resource, &rlim));
|
||||
if (!is_error(ret)) {
|
||||
target_rlim->rlim_cur = tswapl(rlim.rlim_cur);
|
||||
target_rlim->rlim_max = tswapl(rlim.rlim_max);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TARGET_NR_getrusage:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_gettimeofday:
|
||||
|
@ -1317,6 +1335,27 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||
case TARGET_NR_munmap:
|
||||
ret = get_errno(munmap((void *)arg1, arg2));
|
||||
break;
|
||||
case TARGET_NR_mprotect:
|
||||
ret = get_errno(mprotect((void *)arg1, arg2, arg3));
|
||||
break;
|
||||
case TARGET_NR_mremap:
|
||||
ret = get_errno((long)mremap((void *)arg1, arg2, arg3, arg4));
|
||||
break;
|
||||
case TARGET_NR_msync:
|
||||
ret = get_errno(msync((void *)arg1, arg2, arg3));
|
||||
break;
|
||||
case TARGET_NR_mlock:
|
||||
ret = get_errno(mlock((void *)arg1, arg2));
|
||||
break;
|
||||
case TARGET_NR_munlock:
|
||||
ret = get_errno(munlock((void *)arg1, arg2));
|
||||
break;
|
||||
case TARGET_NR_mlockall:
|
||||
ret = get_errno(mlockall(arg1));
|
||||
break;
|
||||
case TARGET_NR_munlockall:
|
||||
ret = get_errno(munlockall());
|
||||
break;
|
||||
case TARGET_NR_truncate:
|
||||
ret = get_errno(truncate((const char *)arg1, arg2));
|
||||
break;
|
||||
|
@ -1506,9 +1545,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||
#endif
|
||||
case TARGET_NR_adjtimex:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_mprotect:
|
||||
ret = get_errno(mprotect((void *)arg1, arg2, arg3));
|
||||
break;
|
||||
case TARGET_NR_create_module:
|
||||
case TARGET_NR_init_module:
|
||||
case TARGET_NR_delete_module:
|
||||
|
@ -1532,9 +1568,11 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||
case TARGET_NR_afs_syscall:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_setfsuid:
|
||||
goto unimplemented;
|
||||
ret = get_errno(setfsuid(arg1));
|
||||
break;
|
||||
case TARGET_NR_setfsgid:
|
||||
goto unimplemented;
|
||||
ret = get_errno(setfsgid(arg1));
|
||||
break;
|
||||
case TARGET_NR__llseek:
|
||||
{
|
||||
int64_t res;
|
||||
|
@ -1596,10 +1634,31 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||
ret = do_select(arg1, (void *)arg2, (void *)arg3, (void *)arg4,
|
||||
(void *)arg5);
|
||||
break;
|
||||
case TARGET_NR_poll:
|
||||
{
|
||||
struct target_pollfd *target_pfd = (void *)arg1;
|
||||
unsigned int nfds = arg2;
|
||||
int timeout = arg3;
|
||||
struct pollfd *pfd;
|
||||
int i;
|
||||
|
||||
pfd = alloca(sizeof(struct pollfd) * nfds);
|
||||
for(i = 0; i < nfds; i++) {
|
||||
pfd->fd = tswap32(target_pfd->fd);
|
||||
pfd->events = tswap16(target_pfd->events);
|
||||
}
|
||||
ret = get_errno(poll(pfd, nfds, timeout));
|
||||
if (!is_error(ret)) {
|
||||
for(i = 0; i < nfds; i++) {
|
||||
target_pfd->revents = tswap16(pfd->revents);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TARGET_NR_flock:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_msync:
|
||||
ret = get_errno(msync((void *)arg1, arg2, arg3));
|
||||
/* NOTE: the flock constant seems to be the same for every
|
||||
Linux platform */
|
||||
ret = get_errno(flock(arg1, arg2));
|
||||
break;
|
||||
case TARGET_NR_readv:
|
||||
{
|
||||
|
@ -1638,18 +1697,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||
goto unimplemented;
|
||||
case TARGET_NR__sysctl:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_mlock:
|
||||
ret = get_errno(mlock((void *)arg1, arg2));
|
||||
break;
|
||||
case TARGET_NR_munlock:
|
||||
ret = get_errno(munlock((void *)arg1, arg2));
|
||||
break;
|
||||
case TARGET_NR_mlockall:
|
||||
ret = get_errno(mlockall(arg1));
|
||||
break;
|
||||
case TARGET_NR_munlockall:
|
||||
ret = get_errno(munlockall());
|
||||
break;
|
||||
case TARGET_NR_sched_setparam:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_sched_getparam:
|
||||
|
@ -1681,12 +1728,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||
}
|
||||
break;
|
||||
|
||||
case TARGET_NR_mremap:
|
||||
case TARGET_NR_setresuid:
|
||||
case TARGET_NR_getresuid:
|
||||
case TARGET_NR_vm86:
|
||||
case TARGET_NR_query_module:
|
||||
case TARGET_NR_poll:
|
||||
case TARGET_NR_nfsservctl:
|
||||
case TARGET_NR_setresgid:
|
||||
case TARGET_NR_getresgid:
|
||||
|
@ -1800,7 +1845,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||
goto unimplemented;
|
||||
default:
|
||||
unimplemented:
|
||||
gemu_log("Unsupported syscall: %d\n", num);
|
||||
gemu_log("gemu: Unsupported syscall: %d\n", num);
|
||||
ret = -ENOSYS;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -150,6 +150,17 @@ struct target_sigaction;
|
|||
int do_sigaction(int sig, const struct target_sigaction *act,
|
||||
struct target_sigaction *oact);
|
||||
|
||||
struct target_rlimit {
|
||||
target_ulong rlim_cur;
|
||||
target_ulong rlim_max;
|
||||
};
|
||||
|
||||
struct target_pollfd {
|
||||
int fd; /* file descriptor */
|
||||
short events; /* requested events */
|
||||
short revents; /* returned events */
|
||||
};
|
||||
|
||||
/* Networking ioctls */
|
||||
#define TARGET_SIOCADDRT 0x890B /* add routing table entry */
|
||||
#define TARGET_SIOCDELRT 0x890C /* delete routing table entry */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue