diff options
author | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2003-03-23 16:49:39 +0000 |
---|---|---|
committer | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2003-03-23 16:49:39 +0000 |
commit | 9de5e440b9f6a6c6305c0b81d1df4ddcc5a4b966 (patch) | |
tree | 718d0257eb2e9cac1196bd8ca83dfd11c15fd475 /linux-user | |
parent | 66fb9763af9cd743158957e8c9c2559d922b1c22 (diff) | |
download | qemu-9de5e440b9f6a6c6305c0b81d1df4ddcc5a4b966.tar.gz qemu-9de5e440b9f6a6c6305c0b81d1df4ddcc5a4b966.tar.bz2 qemu-9de5e440b9f6a6c6305c0b81d1df4ddcc5a4b966.zip |
better signal/exception support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@42 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'linux-user')
-rw-r--r-- | linux-user/elfload.c | 3 | ||||
-rw-r--r-- | linux-user/ioctls.h | 6 | ||||
-rw-r--r-- | linux-user/main.c | 52 | ||||
-rw-r--r-- | linux-user/qemu.h | 33 | ||||
-rw-r--r-- | linux-user/signal.c | 244 | ||||
-rw-r--r-- | linux-user/syscall.c | 115 | ||||
-rw-r--r-- | linux-user/syscall_defs.h | 11 |
7 files changed, 335 insertions, 129 deletions
diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 43d989e9a0..285d8f5c73 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -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, diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index eeefcac3ee..f075aff4d5 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -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)) diff --git a/linux-user/main.c b/linux-user/main.c index bcaa4be161..fba23a0132 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -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; diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 77e9ecadd9..862695511c 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -3,30 +3,12 @@ #include "thunk.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 <signal.h> +#include "syscall_defs.h" +#ifdef TARGET_I386 +#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 diff --git a/linux-user/signal.c b/linux-user/signal.c index 61baf995ae..3e792ae699 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -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); + 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; + } +} + +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: finish it */ -void target_to_host_siginfo(siginfo_t *info, target_siginfo_t *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; } diff --git a/linux-user/syscall.c b/linux-user/syscall.c index dbe3de3fdf..ab78fbb0df 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -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; } diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index b83aeacebd..9b2f42a73f 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -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 */ |