X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=linux-user%2Fsyscall.c;h=753a47cd2d8a19db414e029f5cbab865a24d0f60;hb=2c0262afa75d7d6cb68217f9a7587170ed3cd5b3;hp=2d8804e12a36c5d603d91323cd13dbb8ed5055ee;hpb=5cd4393b14b68a4e80a3ffa74c04efff2b9590a5;p=qemu diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 2d8804e..753a47c 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -39,7 +40,9 @@ #include #include #include +#include //#include +#include #define termios host_termios #define winsize host_winsize @@ -55,24 +58,138 @@ #include #include #include +#include #include "qemu.h" //#define DEBUG -#ifndef PAGE_SIZE -#define PAGE_SIZE 4096 -#define PAGE_MASK ~(PAGE_SIZE - 1) -#endif - //#include #define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2]) #define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2]) -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); + +#if defined(__powerpc__) +#undef __syscall_nr +#undef __sc_loadargs_0 +#undef __sc_loadargs_1 +#undef __sc_loadargs_2 +#undef __sc_loadargs_3 +#undef __sc_loadargs_4 +#undef __sc_loadargs_5 +#undef __sc_asm_input_0 +#undef __sc_asm_input_1 +#undef __sc_asm_input_2 +#undef __sc_asm_input_3 +#undef __sc_asm_input_4 +#undef __sc_asm_input_5 +#undef _syscall0 +#undef _syscall1 +#undef _syscall2 +#undef _syscall3 +#undef _syscall4 +#undef _syscall5 + +/* need to redefine syscalls as Linux kernel defines are incorrect for + the clobber list */ +/* On powerpc a system call basically clobbers the same registers like a + * function call, with the exception of LR (which is needed for the + * "sc; bnslr" sequence) and CR (where only CR0.SO is clobbered to signal + * an error return status). + */ + +#define __syscall_nr(nr, type, name, args...) \ + unsigned long __sc_ret, __sc_err; \ + { \ + register unsigned long __sc_0 __asm__ ("r0"); \ + register unsigned long __sc_3 __asm__ ("r3"); \ + register unsigned long __sc_4 __asm__ ("r4"); \ + register unsigned long __sc_5 __asm__ ("r5"); \ + register unsigned long __sc_6 __asm__ ("r6"); \ + register unsigned long __sc_7 __asm__ ("r7"); \ + \ + __sc_loadargs_##nr(name, args); \ + __asm__ __volatile__ \ + ("sc \n\t" \ + "mfcr %0 " \ + : "=&r" (__sc_0), \ + "=&r" (__sc_3), "=&r" (__sc_4), \ + "=&r" (__sc_5), "=&r" (__sc_6), \ + "=&r" (__sc_7) \ + : __sc_asm_input_##nr \ + : "cr0", "ctr", "memory", \ + "r8", "r9", "r10","r11", "r12"); \ + __sc_ret = __sc_3; \ + __sc_err = __sc_0; \ + } \ + if (__sc_err & 0x10000000) \ + { \ + errno = __sc_ret; \ + __sc_ret = -1; \ + } \ + return (type) __sc_ret + +#define __sc_loadargs_0(name, dummy...) \ + __sc_0 = __NR_##name +#define __sc_loadargs_1(name, arg1) \ + __sc_loadargs_0(name); \ + __sc_3 = (unsigned long) (arg1) +#define __sc_loadargs_2(name, arg1, arg2) \ + __sc_loadargs_1(name, arg1); \ + __sc_4 = (unsigned long) (arg2) +#define __sc_loadargs_3(name, arg1, arg2, arg3) \ + __sc_loadargs_2(name, arg1, arg2); \ + __sc_5 = (unsigned long) (arg3) +#define __sc_loadargs_4(name, arg1, arg2, arg3, arg4) \ + __sc_loadargs_3(name, arg1, arg2, arg3); \ + __sc_6 = (unsigned long) (arg4) +#define __sc_loadargs_5(name, arg1, arg2, arg3, arg4, arg5) \ + __sc_loadargs_4(name, arg1, arg2, arg3, arg4); \ + __sc_7 = (unsigned long) (arg5) + +#define __sc_asm_input_0 "0" (__sc_0) +#define __sc_asm_input_1 __sc_asm_input_0, "1" (__sc_3) +#define __sc_asm_input_2 __sc_asm_input_1, "2" (__sc_4) +#define __sc_asm_input_3 __sc_asm_input_2, "3" (__sc_5) +#define __sc_asm_input_4 __sc_asm_input_3, "4" (__sc_6) +#define __sc_asm_input_5 __sc_asm_input_4, "5" (__sc_7) + +#define _syscall0(type,name) \ +type name(void) \ +{ \ + __syscall_nr(0, type, name); \ +} + +#define _syscall1(type,name,type1,arg1) \ +type name(type1 arg1) \ +{ \ + __syscall_nr(1, type, name, arg1); \ +} + +#define _syscall2(type,name,type1,arg1,type2,arg2) \ +type name(type1 arg1, type2 arg2) \ +{ \ + __syscall_nr(2, type, name, arg1, arg2); \ +} + +#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ +type name(type1 arg1, type2 arg2, type3 arg3) \ +{ \ + __syscall_nr(3, type, name, arg1, arg2, arg3); \ +} + +#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ +type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ +{ \ + __syscall_nr(4, type, name, arg1, arg2, arg3, arg4); \ +} + +#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \ +type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ +{ \ + __syscall_nr(5, type, name, arg1, arg2, arg3, arg4, arg5); \ +} +#endif #define __NR_sys_uname __NR_uname #define __NR_sys_getcwd1 __NR_getcwd @@ -82,6 +199,10 @@ long do_rt_sigreturn(CPUX86State *env); #define __NR_sys_getdents64 __NR_getdents64 #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo +#if defined(__alpha__) || defined (__ia64__) +#define __NR__llseek __NR_lseek +#endif + #ifdef __NR_gettid _syscall0(int, gettid) #else @@ -98,6 +219,9 @@ _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, _syscall2(int,sys_statfs,const char *,path,struct kernel_statfs *,buf) _syscall2(int,sys_fstatfs,int,fd,struct kernel_statfs *,buf) _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo) +#ifdef __NR_exit_group +_syscall1(int,exit_group,int,error_code) +#endif extern int personality(int); extern int flock(int, int); @@ -107,6 +231,7 @@ extern int setresuid(uid_t, uid_t, uid_t); extern int getresuid(uid_t *, uid_t *, uid_t *); extern int setresgid(gid_t, gid_t, gid_t); extern int getresgid(gid_t *, gid_t *, gid_t *); +extern int setgroups(int, gid_t *); static inline long get_errno(long ret) { @@ -141,7 +266,7 @@ static long do_brk(char *new_brk) if (new_brk < target_original_brk) return -ENOMEM; - brk_page = (char *)(((unsigned long)target_brk + PAGE_SIZE - 1) & PAGE_MASK); + brk_page = (char *)HOST_PAGE_ALIGN((unsigned long)target_brk); /* If the new brk is less than this, set it and we're done... */ if (new_brk < brk_page) { @@ -150,11 +275,10 @@ static long do_brk(char *new_brk) } /* We need to allocate more memory after the brk... */ - new_alloc_size = ((new_brk - brk_page + 1)+(PAGE_SIZE-1)) & PAGE_MASK; - mapped_addr = get_errno((long)mmap((caddr_t)brk_page, new_alloc_size, - PROT_READ|PROT_WRITE, - MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0)); - + new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1); + mapped_addr = get_errno(target_mmap((unsigned long)brk_page, new_alloc_size, + PROT_READ|PROT_WRITE, + MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0)); if (is_error(mapped_addr)) { return mapped_addr; } else { @@ -166,7 +290,7 @@ static long do_brk(char *new_brk) static inline fd_set *target_to_host_fds(fd_set *fds, target_long *target_fds, int n) { -#if !defined(BSWP_NEEDED) && !defined(WORD_BIGENDIAN) +#if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN) return (fd_set *)target_fds; #else int i, b; @@ -188,7 +312,7 @@ static inline fd_set *target_to_host_fds(fd_set *fds, static inline void host_to_target_fds(target_long *target_fds, fd_set *fds, int n) { -#if !defined(BSWP_NEEDED) && !defined(WORD_BIGENDIAN) +#if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN) /* nothing to do */ #else int i, nw, j, k; @@ -209,6 +333,44 @@ static inline void host_to_target_fds(target_long *target_fds, #endif } +#if defined(__alpha__) +#define HOST_HZ 1024 +#else +#define HOST_HZ 100 +#endif + +static inline long host_to_target_clock_t(long ticks) +{ +#if HOST_HZ == TARGET_HZ + return ticks; +#else + return ((int64_t)ticks * TARGET_HZ) / HOST_HZ; +#endif +} + +static inline void host_to_target_rusage(struct target_rusage *target_rusage, + const struct rusage *rusage) +{ + target_rusage->ru_utime.tv_sec = tswapl(rusage->ru_utime.tv_sec); + target_rusage->ru_utime.tv_usec = tswapl(rusage->ru_utime.tv_usec); + target_rusage->ru_stime.tv_sec = tswapl(rusage->ru_stime.tv_sec); + target_rusage->ru_stime.tv_usec = tswapl(rusage->ru_stime.tv_usec); + target_rusage->ru_maxrss = tswapl(rusage->ru_maxrss); + target_rusage->ru_ixrss = tswapl(rusage->ru_ixrss); + target_rusage->ru_idrss = tswapl(rusage->ru_idrss); + target_rusage->ru_isrss = tswapl(rusage->ru_isrss); + target_rusage->ru_minflt = tswapl(rusage->ru_minflt); + target_rusage->ru_majflt = tswapl(rusage->ru_majflt); + target_rusage->ru_nswap = tswapl(rusage->ru_nswap); + target_rusage->ru_inblock = tswapl(rusage->ru_inblock); + target_rusage->ru_oublock = tswapl(rusage->ru_oublock); + target_rusage->ru_msgsnd = tswapl(rusage->ru_msgsnd); + target_rusage->ru_msgrcv = tswapl(rusage->ru_msgrcv); + target_rusage->ru_nsignals = tswapl(rusage->ru_nsignals); + target_rusage->ru_nvcsw = tswapl(rusage->ru_nvcsw); + target_rusage->ru_nivcsw = tswapl(rusage->ru_nivcsw); +} + static inline void target_to_host_timeval(struct timeval *tv, const struct target_timeval *target_tv) { @@ -256,55 +418,267 @@ static long do_select(long n, return ret; } -static long do_socketcall(int num, long *vptr) +static inline void target_to_host_sockaddr(struct sockaddr *addr, + struct target_sockaddr *target_addr, + socklen_t len) +{ + memcpy(addr, target_addr, len); + addr->sa_family = tswap16(target_addr->sa_family); +} + +static inline void host_to_target_sockaddr(struct target_sockaddr *target_addr, + struct sockaddr *addr, + socklen_t len) +{ + memcpy(target_addr, addr, len); + target_addr->sa_family = tswap16(addr->sa_family); +} + +static inline void target_to_host_cmsg(struct msghdr *msgh, + struct target_msghdr *target_msgh) +{ + struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh); + struct target_cmsghdr *target_cmsg = TARGET_CMSG_FIRSTHDR(target_msgh); + socklen_t space = 0; + + while (cmsg && target_cmsg) { + void *data = CMSG_DATA(cmsg); + void *target_data = TARGET_CMSG_DATA(target_cmsg); + + int len = tswapl(target_cmsg->cmsg_len) + - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr)); + + space += CMSG_SPACE(len); + if (space > msgh->msg_controllen) { + space -= CMSG_SPACE(len); + gemu_log("Host cmsg overflow"); + break; + } + + 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) { + gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type); + memcpy(data, target_data, len); + } else { + int *fd = (int *)data; + int *target_fd = (int *)target_data; + int i, numfds = len / sizeof(int); + + for (i = 0; i < numfds; i++) + fd[i] = tswap32(target_fd[i]); + } + + cmsg = CMSG_NXTHDR(msgh, cmsg); + target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg); + } + + msgh->msg_controllen = space; +} + +static inline void host_to_target_cmsg(struct target_msghdr *target_msgh, + struct msghdr *msgh) +{ + struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh); + struct target_cmsghdr *target_cmsg = TARGET_CMSG_FIRSTHDR(target_msgh); + socklen_t space = 0; + + while (cmsg && target_cmsg) { + void *data = CMSG_DATA(cmsg); + void *target_data = TARGET_CMSG_DATA(target_cmsg); + + int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr)); + + space += TARGET_CMSG_SPACE(len); + if (space > tswapl(target_msgh->msg_controllen)) { + space -= TARGET_CMSG_SPACE(len); + gemu_log("Target cmsg overflow"); + break; + } + + target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level); + target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type); + target_cmsg->cmsg_len = tswapl(TARGET_CMSG_LEN(len)); + + if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { + gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type); + memcpy(target_data, data, len); + } else { + int *fd = (int *)data; + int *target_fd = (int *)target_data; + int i, numfds = len / sizeof(int); + + for (i = 0; i < numfds; i++) + target_fd[i] = tswap32(fd[i]); + } + + cmsg = CMSG_NXTHDR(msgh, cmsg); + target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg); + } + + msgh->msg_controllen = tswapl(space); +} + +static long do_setsockopt(int sockfd, int level, int optname, + void *optval, socklen_t optlen) +{ + if (level == SOL_TCP) { + /* TCP options all take an 'int' value. */ + int val; + + if (optlen < sizeof(uint32_t)) + return -EINVAL; + + val = tswap32(*(uint32_t *)optval); + return get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); + } + + else if (level != SOL_SOCKET) { + gemu_log("Unsupported setsockopt level: %d\n", level); + return -ENOSYS; + } + + switch (optname) { + /* Options with 'int' argument. */ + case SO_DEBUG: + case SO_REUSEADDR: + case SO_TYPE: + case SO_ERROR: + case SO_DONTROUTE: + case SO_BROADCAST: + case SO_SNDBUF: + case SO_RCVBUF: + case SO_KEEPALIVE: + case SO_OOBINLINE: + case SO_NO_CHECK: + case SO_PRIORITY: + case SO_BSDCOMPAT: + case SO_PASSCRED: + case SO_TIMESTAMP: + case SO_RCVLOWAT: + case SO_RCVTIMEO: + case SO_SNDTIMEO: + { + int val; + if (optlen < sizeof(uint32_t)) + return -EINVAL; + val = tswap32(*(uint32_t *)optval); + return get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); + } + + default: + gemu_log("Unsupported setsockopt SOL_SOCKET option: %d\n", optname); + return -ENOSYS; + } +} + +static long do_getsockopt(int sockfd, int level, int optname, + void *optval, socklen_t *optlen) +{ + gemu_log("getsockopt not yet supported\n"); + return -ENOSYS; +} + +static long do_socketcall(int num, int32_t *vptr) { long ret; switch(num) { case SOCKOP_socket: - ret = get_errno(socket(vptr[0], vptr[1], vptr[2])); + { + int domain = tswap32(vptr[0]); + int type = tswap32(vptr[1]); + int protocol = tswap32(vptr[2]); + + ret = get_errno(socket(domain, type, protocol)); + } break; case SOCKOP_bind: - ret = get_errno(bind(vptr[0], (struct sockaddr *)vptr[1], vptr[2])); + { + int sockfd = tswap32(vptr[0]); + void *target_addr = (void *)tswap32(vptr[1]); + socklen_t addrlen = tswap32(vptr[2]); + void *addr = alloca(addrlen); + + target_to_host_sockaddr(addr, target_addr, addrlen); + ret = get_errno(bind(sockfd, addr, addrlen)); + } break; case SOCKOP_connect: - ret = get_errno(connect(vptr[0], (struct sockaddr *)vptr[1], vptr[2])); + { + int sockfd = tswap32(vptr[0]); + void *target_addr = (void *)tswap32(vptr[1]); + socklen_t addrlen = tswap32(vptr[2]); + void *addr = alloca(addrlen); + + target_to_host_sockaddr(addr, target_addr, addrlen); + ret = get_errno(connect(sockfd, addr, addrlen)); + } break; case SOCKOP_listen: - ret = get_errno(listen(vptr[0], vptr[1])); + { + int sockfd = tswap32(vptr[0]); + int backlog = tswap32(vptr[1]); + + ret = get_errno(listen(sockfd, backlog)); + } break; case SOCKOP_accept: { - socklen_t size; - size = tswap32(*(int32_t *)vptr[2]); - ret = get_errno(accept(vptr[0], (struct sockaddr *)vptr[1], &size)); - if (!is_error(ret)) - *(int32_t *)vptr[2] = size; + int sockfd = tswap32(vptr[0]); + void *target_addr = (void *)tswap32(vptr[1]); + uint32_t *target_addrlen = (void *)tswap32(vptr[2]); + socklen_t addrlen = tswap32(*target_addrlen); + void *addr = alloca(addrlen); + + ret = get_errno(accept(sockfd, addr, &addrlen)); + if (!is_error(ret)) { + host_to_target_sockaddr(target_addr, addr, addrlen); + *target_addrlen = tswap32(addrlen); + } } break; case SOCKOP_getsockname: { - socklen_t size; - size = tswap32(*(int32_t *)vptr[2]); - ret = get_errno(getsockname(vptr[0], (struct sockaddr *)vptr[1], &size)); - if (!is_error(ret)) - *(int32_t *)vptr[2] = size; + int sockfd = tswap32(vptr[0]); + void *target_addr = (void *)tswap32(vptr[1]); + uint32_t *target_addrlen = (void *)tswap32(vptr[2]); + socklen_t addrlen = tswap32(*target_addrlen); + void *addr = alloca(addrlen); + + ret = get_errno(getsockname(sockfd, addr, &addrlen)); + if (!is_error(ret)) { + host_to_target_sockaddr(target_addr, addr, addrlen); + *target_addrlen = tswap32(addrlen); + } } break; case SOCKOP_getpeername: { - socklen_t size; - size = tswap32(*(int32_t *)vptr[2]); - ret = get_errno(getpeername(vptr[0], (struct sockaddr *)vptr[1], &size)); - if (!is_error(ret)) - *(int32_t *)vptr[2] = size; + int sockfd = tswap32(vptr[0]); + void *target_addr = (void *)tswap32(vptr[1]); + uint32_t *target_addrlen = (void *)tswap32(vptr[2]); + socklen_t addrlen = tswap32(*target_addrlen); + void *addr = alloca(addrlen); + + ret = get_errno(getpeername(sockfd, addr, &addrlen)); + if (!is_error(ret)) { + host_to_target_sockaddr(target_addr, addr, addrlen); + *target_addrlen = tswap32(addrlen); + } } break; case SOCKOP_socketpair: { + int domain = tswap32(vptr[0]); + int type = tswap32(vptr[1]); + int protocol = tswap32(vptr[2]); + int32_t *target_tab = (void *)tswap32(vptr[3]); int tab[2]; - int32_t *target_tab = (int32_t *)vptr[3]; - ret = get_errno(socketpair(vptr[0], vptr[1], vptr[2], tab)); + + ret = get_errno(socketpair(domain, type, protocol, tab)); if (!is_error(ret)) { target_tab[0] = tswap32(tab[0]); target_tab[1] = tswap32(tab[1]); @@ -312,27 +686,64 @@ static long do_socketcall(int num, long *vptr) } break; case SOCKOP_send: - ret = get_errno(send(vptr[0], (void *)vptr[1], vptr[2], vptr[3])); + { + int sockfd = tswap32(vptr[0]); + void *msg = (void *)tswap32(vptr[1]); + size_t len = tswap32(vptr[2]); + int flags = tswap32(vptr[3]); + + ret = get_errno(send(sockfd, msg, len, flags)); + } break; case SOCKOP_recv: - ret = get_errno(recv(vptr[0], (void *)vptr[1], vptr[2], vptr[3])); + { + int sockfd = tswap32(vptr[0]); + void *msg = (void *)tswap32(vptr[1]); + size_t len = tswap32(vptr[2]); + int flags = tswap32(vptr[3]); + + ret = get_errno(recv(sockfd, msg, len, flags)); + } break; case SOCKOP_sendto: - ret = get_errno(sendto(vptr[0], (void *)vptr[1], vptr[2], vptr[3], - (struct sockaddr *)vptr[4], vptr[5])); + { + int sockfd = tswap32(vptr[0]); + void *msg = (void *)tswap32(vptr[1]); + size_t len = tswap32(vptr[2]); + int flags = tswap32(vptr[3]); + void *target_addr = (void *)tswap32(vptr[4]); + socklen_t addrlen = tswap32(vptr[5]); + void *addr = alloca(addrlen); + + target_to_host_sockaddr(addr, target_addr, addrlen); + ret = get_errno(sendto(sockfd, msg, len, flags, addr, addrlen)); + } break; case SOCKOP_recvfrom: { - socklen_t size; - size = tswap32(*(int32_t *)vptr[5]); - ret = get_errno(recvfrom(vptr[0], (void *)vptr[1], vptr[2], - vptr[3], (struct sockaddr *)vptr[4], &size)); - if (!is_error(ret)) - *(int32_t *)vptr[5] = size; + int sockfd = tswap32(vptr[0]); + void *msg = (void *)tswap32(vptr[1]); + size_t len = tswap32(vptr[2]); + int flags = tswap32(vptr[3]); + void *target_addr = (void *)tswap32(vptr[4]); + uint32_t *target_addrlen = (void *)tswap32(vptr[5]); + socklen_t addrlen = tswap32(*target_addrlen); + void *addr = alloca(addrlen); + + ret = get_errno(recvfrom(sockfd, msg, len, flags, addr, &addrlen)); + if (!is_error(ret)) { + host_to_target_sockaddr(target_addr, addr, addrlen); + *target_addrlen = tswap32(addrlen); + } } break; case SOCKOP_shutdown: - ret = get_errno(shutdown(vptr[0], vptr[1])); + { + int sockfd = tswap32(vptr[0]); + int how = tswap32(vptr[1]); + + ret = get_errno(shutdown(sockfd, how)); + } break; case SOCKOP_sendmsg: case SOCKOP_recvmsg: @@ -344,11 +755,11 @@ static long do_socketcall(int num, long *vptr) struct iovec *vec; struct target_iovec *target_vec; - msgp = (void *)vptr[1]; + msgp = (void *)tswap32(vptr[1]); msg.msg_name = (void *)tswapl(msgp->msg_name); msg.msg_namelen = tswapl(msgp->msg_namelen); - msg.msg_control = (void *)tswapl(msgp->msg_control); - msg.msg_controllen = tswapl(msgp->msg_controllen); + msg.msg_controllen = 2 * tswapl(msgp->msg_controllen); + msg.msg_control = alloca(msg.msg_controllen); msg.msg_flags = tswap32(msgp->msg_flags); count = tswapl(msgp->msg_iovlen); @@ -361,17 +772,43 @@ static long do_socketcall(int num, long *vptr) msg.msg_iovlen = count; msg.msg_iov = vec; - fd = vptr[0]; - flags = vptr[2]; - if (num == SOCKOP_sendmsg) - ret = sendmsg(fd, &msg, flags); - else - ret = recvmsg(fd, &msg, flags); - ret = get_errno(ret); + fd = tswap32(vptr[0]); + flags = tswap32(vptr[2]); + if (num == SOCKOP_sendmsg) { + target_to_host_cmsg(&msg, msgp); + ret = get_errno(sendmsg(fd, &msg, flags)); + } else { + ret = get_errno(recvmsg(fd, &msg, flags)); + if (!is_error(ret)) + host_to_target_cmsg(msgp, &msg); + } } break; case SOCKOP_setsockopt: + { + int sockfd = tswap32(vptr[0]); + int level = tswap32(vptr[1]); + int optname = tswap32(vptr[2]); + void *optval = (void *)tswap32(vptr[3]); + socklen_t optlen = tswap32(vptr[4]); + + ret = do_setsockopt(sockfd, level, optname, optval, optlen); + } + break; case SOCKOP_getsockopt: + { + int sockfd = tswap32(vptr[0]); + int level = tswap32(vptr[1]); + int optname = tswap32(vptr[2]); + void *optval = (void *)tswap32(vptr[3]); + uint32_t *target_len = (void *)tswap32(vptr[4]); + socklen_t optlen = tswap32(*target_len); + + ret = do_getsockopt(sockfd, level, optname, optval, &optlen); + if (!is_error(ret)) + *target_len = tswap32(optlen); + } + break; default: gemu_log("Unsupported socketcall: %d\n", num); ret = -ENOSYS; @@ -398,8 +835,8 @@ enum { #undef STRUCT_SPECIAL typedef struct IOCTLEntry { - int target_cmd; - int host_cmd; + unsigned int target_cmd; + unsigned int host_cmd; const char *name; int access; const argtype arg_type[5]; @@ -411,7 +848,7 @@ typedef struct IOCTLEntry { #define MAX_STRUCT_SIZE 4096 -const IOCTLEntry ioctl_entries[] = { +IOCTLEntry ioctl_entries[] = { #define IOCTL(cmd, access, types...) \ { TARGET_ ## cmd, cmd, #cmd, access, { types } }, #include "ioctls.h" @@ -654,7 +1091,19 @@ StructEntry struct_termios_def = { .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) }, }; -#ifdef TARGET_I386 +static bitmask_transtbl mmap_flags_tbl[] = { + { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED }, + { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE }, + { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED }, + { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS }, + { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN }, + { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE }, + { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE }, + { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED }, + { 0, 0, 0, 0 } +}; + +#if defined(TARGET_I386) /* NOTE: there is really one LDT for all the threads */ uint8_t *ldt_table; @@ -743,7 +1192,7 @@ static int write_ldt(CPUX86State *env, 0x7000; if (!oldmode) entry_2 |= (useable << 20); - + /* Install the new entry ... */ install: lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3)); @@ -771,78 +1220,7 @@ int do_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecount return ret; } -/* vm86 emulation */ - -#define SAFE_MASK (0xDD5) - -int do_vm86(CPUX86State *env, long subfunction, - struct target_vm86plus_struct * target_v86) -{ - TaskState *ts = env->opaque; - int ret; - - switch (subfunction) { - case TARGET_VM86_REQUEST_IRQ: - case TARGET_VM86_FREE_IRQ: - case TARGET_VM86_GET_IRQ_BITS: - case TARGET_VM86_GET_AND_RESET_IRQ: - gemu_log("qemu: unsupported vm86 subfunction (%ld)\n", subfunction); - ret = -EINVAL; - goto out; - case TARGET_VM86_PLUS_INSTALL_CHECK: - /* NOTE: on old vm86 stuff this will return the error - from verify_area(), because the subfunction is - interpreted as (invalid) address to vm86_struct. - So the installation check works. - */ - ret = 0; - goto out; - } - - ts->target_v86 = target_v86; - - /* save current CPU regs */ - ts->vm86_saved_regs.eax = 0; /* default vm86 syscall return code */ - ts->vm86_saved_regs.ebx = env->regs[R_EBX]; - ts->vm86_saved_regs.ecx = env->regs[R_ECX]; - ts->vm86_saved_regs.edx = env->regs[R_EDX]; - ts->vm86_saved_regs.esi = env->regs[R_ESI]; - ts->vm86_saved_regs.edi = env->regs[R_EDI]; - ts->vm86_saved_regs.ebp = env->regs[R_EBP]; - ts->vm86_saved_regs.esp = env->regs[R_ESP]; - ts->vm86_saved_regs.eflags = env->eflags; - ts->vm86_saved_regs.eip = env->eip; - ts->vm86_saved_regs.cs = env->segs[R_CS]; - ts->vm86_saved_regs.ss = env->segs[R_SS]; - ts->vm86_saved_regs.ds = env->segs[R_DS]; - ts->vm86_saved_regs.es = env->segs[R_ES]; - ts->vm86_saved_regs.fs = env->segs[R_FS]; - ts->vm86_saved_regs.gs = env->segs[R_GS]; - - /* build vm86 CPU state */ - env->eflags = (env->eflags & ~SAFE_MASK) | - (tswap32(target_v86->regs.eflags) & SAFE_MASK) | VM_MASK; - - env->regs[R_EBX] = tswap32(target_v86->regs.ebx); - env->regs[R_ECX] = tswap32(target_v86->regs.ecx); - env->regs[R_EDX] = tswap32(target_v86->regs.edx); - env->regs[R_ESI] = tswap32(target_v86->regs.esi); - env->regs[R_EDI] = tswap32(target_v86->regs.edi); - env->regs[R_EBP] = tswap32(target_v86->regs.ebp); - env->regs[R_ESP] = tswap32(target_v86->regs.esp); - env->eip = tswap32(target_v86->regs.eip); - cpu_x86_load_seg(env, R_CS, tswap16(target_v86->regs.cs)); - cpu_x86_load_seg(env, R_SS, tswap16(target_v86->regs.ss)); - cpu_x86_load_seg(env, R_DS, tswap16(target_v86->regs.ds)); - cpu_x86_load_seg(env, R_ES, tswap16(target_v86->regs.es)); - cpu_x86_load_seg(env, R_FS, tswap16(target_v86->regs.fs)); - cpu_x86_load_seg(env, R_GS, tswap16(target_v86->regs.gs)); - ret = tswap32(target_v86->regs.eax); /* eax will be restored at - the end of the syscall */ - /* now the virtual CPU is ready for vm86 execution ! */ - out: - return ret; -} +#endif /* defined(TARGET_I386) */ /* this stack is the equivalent of the kernel stack associated with a thread/process */ @@ -850,22 +1228,20 @@ int do_vm86(CPUX86State *env, long subfunction, static int clone_func(void *arg) { - CPUX86State *env = arg; + CPUState *env = arg; cpu_loop(env); /* never exits */ return 0; } -int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp) +int do_fork(CPUState *env, unsigned int flags, unsigned long newsp) { int ret; TaskState *ts; uint8_t *new_stack; - CPUX86State *new_env; + CPUState *new_env; if (flags & CLONE_VM) { - if (!newsp) - newsp = env->regs[R_ESP]; ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE); memset(ts, 0, sizeof(TaskState)); new_stack = ts->stack; @@ -874,12 +1250,27 @@ int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp) ts->next = first_task_state; first_task_state = ts; /* we create a new CPU instance. */ - new_env = cpu_x86_init(); - memcpy(new_env, env, sizeof(CPUX86State)); + new_env = cpu_init(); + memcpy(new_env, env, sizeof(CPUState)); +#if defined(TARGET_I386) + if (!newsp) + newsp = env->regs[R_ESP]; new_env->regs[R_ESP] = newsp; new_env->regs[R_EAX] = 0; +#elif defined(TARGET_ARM) + if (!newsp) + newsp = env->regs[13]; + new_env->regs[13] = newsp; + new_env->regs[0] = 0; +#else +#error unsupported target CPU +#endif new_env->opaque = ts; - ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); +#ifdef __ia64__ + ret = clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); +#else + ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); +#endif } else { /* if no CLONE_VM, we consider it is a fork */ if ((flags & ~CSIGNAL) != 0) @@ -889,7 +1280,48 @@ int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp) return ret; } -#endif +static long do_fcntl(int fd, int cmd, unsigned long arg) +{ + struct flock fl; + struct target_flock *target_fl = (void *)arg; + long ret; + + switch(cmd) { + case TARGET_F_GETLK: + ret = fcntl(fd, cmd, &fl); + if (ret == 0) { + target_fl->l_type = tswap16(fl.l_type); + target_fl->l_whence = tswap16(fl.l_whence); + target_fl->l_start = tswapl(fl.l_start); + target_fl->l_len = tswapl(fl.l_len); + target_fl->l_pid = tswapl(fl.l_pid); + } + break; + + case TARGET_F_SETLK: + case TARGET_F_SETLKW: + fl.l_type = tswap16(target_fl->l_type); + fl.l_whence = tswap16(target_fl->l_whence); + fl.l_start = tswapl(target_fl->l_start); + fl.l_len = tswapl(target_fl->l_len); + fl.l_pid = tswapl(target_fl->l_pid); + ret = fcntl(fd, cmd, &fl); + break; + + case TARGET_F_GETLK64: + case TARGET_F_SETLK64: + case TARGET_F_SETLKW64: + ret = -1; + errno = EINVAL; + break; + + default: + ret = fcntl(fd, cmd, arg); + break; + } + return ret; +} + #define high2lowuid(x) (x) #define high2lowgid(x) (x) @@ -898,11 +1330,43 @@ int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp) void syscall_init(void) { + IOCTLEntry *ie; + const argtype *arg_type; + int size; + #define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def); #define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def); #include "syscall_types.h" #undef STRUCT #undef STRUCT_SPECIAL + + /* we patch the ioctl size if necessary. We rely on the fact that + no ioctl has all the bits at '1' in the size field */ + ie = ioctl_entries; + while (ie->target_cmd != 0) { + if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) == + TARGET_IOC_SIZEMASK) { + 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_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) | + (size << TARGET_IOC_SIZESHIFT); + } + /* automatic consistency check if same arch */ +#if defined(__i386__) && defined(TARGET_I386) + if (ie->target_cmd != ie->host_cmd) { + fprintf(stderr, "ERROR: ioctl: target=0x%x host=0x%x\n", + ie->target_cmd, ie->host_cmd); + } +#endif + ie++; + } } long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, @@ -925,13 +1389,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = 0; /* avoid warning */ break; case TARGET_NR_read: + page_unprotect_range((void *)arg2, arg3); ret = get_errno(read(arg1, (void *)arg2, arg3)); break; case TARGET_NR_write: ret = get_errno(write(arg1, (void *)arg2, arg3)); break; case TARGET_NR_open: - ret = get_errno(open((const char *)arg1, arg2, arg3)); + ret = get_errno(open(path((const char *)arg1), arg2, arg3)); break; case TARGET_NR_close: ret = get_errno(close(arg1)); @@ -960,7 +1425,32 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(unlink((const char *)arg1)); break; case TARGET_NR_execve: - ret = get_errno(execve((const char *)arg1, (void *)arg2, (void *)arg3)); + { + char **argp, **envp; + int argc, envc; + uint32_t *p; + char **q; + + argc = 0; + for (p = (void *)arg2; *p; p++) + argc++; + envc = 0; + for (p = (void *)arg3; *p; p++) + envc++; + + argp = alloca((argc + 1) * sizeof(void *)); + envp = alloca((envc + 1) * sizeof(void *)); + + for (p = (void *)arg2, q = argp; *p; p++, q++) + *q = (void *)tswap32(*p); + *q = NULL; + + for (p = (void *)arg3, q = envp; *p; p++, q++) + *q = (void *)tswap32(*p); + *q = NULL; + + ret = get_errno(execve((const char *)arg1, argp, envp)); + } break; case TARGET_NR_chdir: ret = get_errno(chdir((const char *)arg1)); @@ -1066,7 +1556,20 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } break; case TARGET_NR_times: - goto unimplemented; + { + struct target_tms *tmsp = (void *)arg1; + struct tms tms; + ret = get_errno(times(&tms)); + if (tmsp) { + tmsp->tms_utime = tswapl(host_to_target_clock_t(tms.tms_utime)); + tmsp->tms_stime = tswapl(host_to_target_clock_t(tms.tms_stime)); + tmsp->tms_cutime = tswapl(host_to_target_clock_t(tms.tms_cutime)); + tmsp->tms_cstime = tswapl(host_to_target_clock_t(tms.tms_cstime)); + } + if (!is_error(ret)) + ret = host_to_target_clock_t(ret); + } + break; case TARGET_NR_prof: goto unimplemented; case TARGET_NR_setgid: @@ -1094,15 +1597,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = do_ioctl(arg1, arg2, arg3); break; case TARGET_NR_fcntl: - switch(arg2) { - case F_GETLK: - case F_SETLK: - case F_SETLKW: - goto unimplemented; - default: - ret = get_errno(fcntl(arg1, arg2, arg3)); - break; - } + ret = get_errno(do_fcntl(arg1, arg2, arg3)); break; case TARGET_NR_mpx: goto unimplemented; @@ -1352,7 +1847,15 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } break; case TARGET_NR_getrusage: - goto unimplemented; + { + struct rusage rusage; + struct target_rusage *target_rusage = (void *)arg2; + ret = get_errno(getrusage(arg1, &rusage)); + if (!is_error(ret)) { + host_to_target_rusage(target_rusage, &rusage); + } + } + break; case TARGET_NR_gettimeofday: { struct target_timeval *target_tv = (void *)arg1; @@ -1372,18 +1875,52 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } break; case TARGET_NR_getgroups: - goto unimplemented; + { + int gidsetsize = arg1; + uint16_t *target_grouplist = (void *)arg2; + gid_t *grouplist; + int i; + + grouplist = alloca(gidsetsize * sizeof(gid_t)); + ret = get_errno(getgroups(gidsetsize, grouplist)); + if (!is_error(ret)) { + for(i = 0;i < gidsetsize; i++) + target_grouplist[i] = tswap16(grouplist[i]); + } + } + break; case TARGET_NR_setgroups: - goto unimplemented; + { + int gidsetsize = arg1; + uint16_t *target_grouplist = (void *)arg2; + gid_t *grouplist; + int i; + + grouplist = alloca(gidsetsize * sizeof(gid_t)); + for(i = 0;i < gidsetsize; i++) + grouplist[i] = tswap16(target_grouplist[i]); + ret = get_errno(setgroups(gidsetsize, grouplist)); + } + break; case TARGET_NR_select: - goto unimplemented; + { + struct target_sel_arg_struct *sel = (void *)arg1; + sel->n = tswapl(sel->n); + sel->inp = tswapl(sel->inp); + sel->outp = tswapl(sel->outp); + sel->exp = tswapl(sel->exp); + sel->tvp = tswapl(sel->tvp); + ret = do_select(sel->n, (void *)sel->inp, (void *)sel->outp, + (void *)sel->exp, (void *)sel->tvp); + } + break; case TARGET_NR_symlink: ret = get_errno(symlink((const char *)arg1, (const char *)arg2)); break; case TARGET_NR_oldlstat: goto unimplemented; case TARGET_NR_readlink: - ret = get_errno(readlink((const char *)arg1, (char *)arg2, arg3)); + ret = get_errno(readlink(path((const char *)arg1), (char *)arg2, arg3)); break; case TARGET_NR_uselib: goto unimplemented; @@ -1394,8 +1931,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, goto unimplemented; case TARGET_NR_readdir: goto unimplemented; -#ifdef TARGET_I386 case TARGET_NR_mmap: +#if defined(TARGET_I386) || defined(TARGET_ARM) { uint32_t v1, v2, v3, v4, v5, v6, *vptr; vptr = (uint32_t *)arg1; @@ -1405,25 +1942,31 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, v4 = tswap32(vptr[3]); v5 = tswap32(vptr[4]); v6 = tswap32(vptr[5]); - ret = get_errno((long)mmap((void *)v1, v2, v3, v4, v5, v6)); + ret = get_errno(target_mmap(v1, v2, v3, + target_to_host_bitmask(v4, mmap_flags_tbl), + v5, v6)); } - break; -#endif -#ifdef TARGET_I386 - case TARGET_NR_mmap2: #else - case TARGET_NR_mmap: + ret = get_errno(target_mmap(arg1, arg2, arg3, + target_to_host_bitmask(arg4, mmap_flags_tbl), + arg5, + arg6)); #endif - ret = get_errno((long)mmap((void *)arg1, arg2, arg3, arg4, arg5, arg6)); + break; + case TARGET_NR_mmap2: + ret = get_errno(target_mmap(arg1, arg2, arg3, + target_to_host_bitmask(arg4, mmap_flags_tbl), + arg5, + arg6 << TARGET_PAGE_BITS)); break; case TARGET_NR_munmap: - ret = get_errno(munmap((void *)arg1, arg2)); + ret = get_errno(target_munmap(arg1, arg2)); break; case TARGET_NR_mprotect: - ret = get_errno(mprotect((void *)arg1, arg2, arg3)); + ret = get_errno(target_mprotect(arg1, arg2, arg3)); break; case TARGET_NR_mremap: - ret = get_errno((long)mremap((void *)arg1, arg2, arg3, arg4)); + ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5)); break; case TARGET_NR_msync: ret = get_errno(msync((void *)arg1, arg2, arg3)); @@ -1462,7 +2005,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, goto unimplemented; case TARGET_NR_statfs: stfs = (void *)arg2; - ret = get_errno(sys_statfs((const char *)arg1, stfs)); + ret = get_errno(sys_statfs(path((const char *)arg1), stfs)); convert_statfs: if (!is_error(ret)) { tswap32s(&stfs->f_type); @@ -1484,7 +2027,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_ioperm: goto unimplemented; case TARGET_NR_socketcall: - ret = do_socketcall(arg1, (long *)arg2); + ret = do_socketcall(arg1, (int32_t *)arg2); break; case TARGET_NR_syslog: goto unimplemented; @@ -1527,10 +2070,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } break; case TARGET_NR_stat: - ret = get_errno(stat((const char *)arg1, &st)); + ret = get_errno(stat(path((const char *)arg1), &st)); goto do_stat; case TARGET_NR_lstat: - ret = get_errno(lstat((const char *)arg1, &st)); + ret = get_errno(lstat(path((const char *)arg1), &st)); goto do_stat; case TARGET_NR_fstat: { @@ -1548,9 +2091,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, target_st->st_size = tswapl(st.st_size); target_st->st_blksize = tswapl(st.st_blksize); target_st->st_blocks = tswapl(st.st_blocks); - target_st->st_atime = tswapl(st.st_atime); - target_st->st_mtime = tswapl(st.st_mtime); - target_st->st_ctime = tswapl(st.st_ctime); + target_st->target_st_atime = tswapl(st.st_atime); + target_st->target_st_mtime = tswapl(st.st_mtime); + target_st->target_st_ctime = tswapl(st.st_ctime); } } break; @@ -1578,24 +2121,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, if (status_ptr) *status_ptr = tswap32(status); if (target_rusage) { - target_rusage->ru_utime.tv_sec = tswapl(rusage.ru_utime.tv_sec); - target_rusage->ru_utime.tv_usec = tswapl(rusage.ru_utime.tv_usec); - target_rusage->ru_stime.tv_sec = tswapl(rusage.ru_stime.tv_sec); - target_rusage->ru_stime.tv_usec = tswapl(rusage.ru_stime.tv_usec); - target_rusage->ru_maxrss = tswapl(rusage.ru_maxrss); - target_rusage->ru_ixrss = tswapl(rusage.ru_ixrss); - target_rusage->ru_idrss = tswapl(rusage.ru_idrss); - target_rusage->ru_isrss = tswapl(rusage.ru_isrss); - target_rusage->ru_minflt = tswapl(rusage.ru_minflt); - target_rusage->ru_majflt = tswapl(rusage.ru_majflt); - target_rusage->ru_nswap = tswapl(rusage.ru_nswap); - target_rusage->ru_inblock = tswapl(rusage.ru_inblock); - target_rusage->ru_oublock = tswapl(rusage.ru_oublock); - target_rusage->ru_msgsnd = tswapl(rusage.ru_msgsnd); - target_rusage->ru_msgrcv = tswapl(rusage.ru_msgrcv); - target_rusage->ru_nsignals = tswapl(rusage.ru_nsignals); - target_rusage->ru_nvcsw = tswapl(rusage.ru_nvcsw); - target_rusage->ru_nivcsw = tswapl(rusage.ru_nivcsw); + host_to_target_rusage(target_rusage, &rusage); } } } @@ -1613,6 +2139,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_clone: ret = get_errno(do_fork(cpu_env, arg1, arg2)); break; +#ifdef __NR_exit_group + /* new thread calls */ + case TARGET_NR_exit_group: + ret = get_errno(exit_group(arg1)); + break; +#endif case TARGET_NR_setdomainname: ret = get_errno(setdomainname((const char *)arg1, arg2)); break; @@ -1670,7 +2202,47 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_getdents: #if TARGET_LONG_SIZE != 4 #error not supported -#endif +#elif TARGET_LONG_SIZE == 4 && HOST_LONG_SIZE == 8 + { + struct target_dirent *target_dirp = (void *)arg2; + struct dirent *dirp; + long count = arg3; + + dirp = malloc(count); + if (!dirp) + return -ENOMEM; + + ret = get_errno(sys_getdents(arg1, dirp, count)); + if (!is_error(ret)) { + struct dirent *de; + struct target_dirent *tde; + int len = ret; + int reclen, treclen; + int count1, tnamelen; + + count1 = 0; + de = dirp; + tde = target_dirp; + while (len > 0) { + reclen = de->d_reclen; + treclen = reclen - (2 * (sizeof(long) - sizeof(target_long))); + tde->d_reclen = tswap16(treclen); + tde->d_ino = tswapl(de->d_ino); + tde->d_off = tswapl(de->d_off); + tnamelen = treclen - (2 * sizeof(target_long) + 2); + if (tnamelen > 256) + tnamelen = 256; + strncpy(tde->d_name, de->d_name, tnamelen); + de = (struct dirent *)((char *)de + reclen); + len -= reclen; + tde = (struct dirent *)((char *)tde + treclen); + count1 += treclen; + } + ret = count1; + } + free(dirp); + } +#else { struct dirent *dirp = (void *)arg2; long count = arg3; @@ -1693,6 +2265,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } } } +#endif break; case TARGET_NR_getdents64: { @@ -1727,7 +2300,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, unsigned int nfds = arg2; int timeout = arg3; struct pollfd *pfd; - int i; + unsigned int i; pfd = alloca(sizeof(struct pollfd) * nfds); for(i = 0; i < nfds; i++) { @@ -1887,9 +2460,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_prctl: goto unimplemented; case TARGET_NR_pread: - goto unimplemented; + page_unprotect_range((void *)arg2, arg3); + ret = get_errno(pread(arg1, (void *)arg2, arg3, arg4)); + break; case TARGET_NR_pwrite: - goto unimplemented; + ret = get_errno(pwrite(arg1, (void *)arg2, arg3, arg4)); + break; case TARGET_NR_chown: ret = get_errno(chown((const char *)arg1, arg2, arg3)); break; @@ -1912,16 +2488,25 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0)); break; case TARGET_NR_ugetrlimit: - goto unimplemented; + { + struct rlimit rlim; + ret = get_errno(getrlimit(arg1, &rlim)); + if (!is_error(ret)) { + struct target_rlimit *target_rlim = (void *)arg2; + target_rlim->rlim_cur = tswapl(rlim.rlim_cur); + target_rlim->rlim_max = tswapl(rlim.rlim_max); + } + break; + } case TARGET_NR_truncate64: goto unimplemented; case TARGET_NR_ftruncate64: goto unimplemented; case TARGET_NR_stat64: - ret = get_errno(stat((const char *)arg1, &st)); + ret = get_errno(stat(path((const char *)arg1), &st)); goto do_stat64; case TARGET_NR_lstat64: - ret = get_errno(lstat((const char *)arg1, &st)); + ret = get_errno(lstat(path((const char *)arg1), &st)); goto do_stat64; case TARGET_NR_fstat64: { @@ -1929,20 +2514,24 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, do_stat64: if (!is_error(ret)) { struct target_stat64 *target_st = (void *)arg2; + memset(target_st, 0, sizeof(struct target_stat64)); target_st->st_dev = tswap16(st.st_dev); - target_st->st_ino = tswapl(st.st_ino); - target_st->st_mode = tswap16(st.st_mode); - target_st->st_nlink = tswap16(st.st_nlink); - target_st->st_uid = tswap16(st.st_uid); - target_st->st_gid = tswap16(st.st_gid); + target_st->st_ino = tswap64(st.st_ino); +#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO + target_st->__st_ino = tswapl(st.st_ino); +#endif + target_st->st_mode = tswap32(st.st_mode); + target_st->st_nlink = tswap32(st.st_nlink); + target_st->st_uid = tswapl(st.st_uid); + target_st->st_gid = tswapl(st.st_gid); target_st->st_rdev = tswap16(st.st_rdev); /* XXX: better use of kernel struct */ - target_st->st_size = tswapl(st.st_size); + target_st->st_size = tswap64(st.st_size); target_st->st_blksize = tswapl(st.st_blksize); target_st->st_blocks = tswapl(st.st_blocks); - target_st->st_atime = tswapl(st.st_atime); - target_st->st_mtime = tswapl(st.st_mtime); - target_st->st_ctime = tswapl(st.st_ctime); + target_st->target_st_atime = tswapl(st.st_atime); + target_st->target_st_mtime = tswapl(st.st_mtime); + target_st->target_st_ctime = tswapl(st.st_ctime); } } break; @@ -2026,16 +2615,37 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, goto unimplemented; #if TARGET_LONG_BITS == 32 case TARGET_NR_fcntl64: + { + struct flock64 fl; + struct target_flock64 *target_fl = (void *)arg3; + switch(arg2) { case F_GETLK64: + ret = get_errno(fcntl(arg1, arg2, &fl)); + if (ret == 0) { + target_fl->l_type = tswap16(fl.l_type); + target_fl->l_whence = tswap16(fl.l_whence); + target_fl->l_start = tswap64(fl.l_start); + target_fl->l_len = tswap64(fl.l_len); + target_fl->l_pid = tswapl(fl.l_pid); + } + break; + case F_SETLK64: case F_SETLKW64: - goto unimplemented; + fl.l_type = tswap16(target_fl->l_type); + fl.l_whence = tswap16(target_fl->l_whence); + fl.l_start = tswap64(target_fl->l_start); + fl.l_len = tswap64(target_fl->l_len); + fl.l_pid = tswapl(target_fl->l_pid); + ret = get_errno(fcntl(arg1, arg2, &fl)); + break; default: - ret = get_errno(fcntl(arg1, arg2, arg3)); + ret = get_errno(do_fcntl(arg1, arg2, arg3)); break; } - break; + break; + } #endif case TARGET_NR_security: goto unimplemented;