X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=linux-user%2Fsyscall.c;h=5eb5b3931ff2d27954f973b3049e3609fb7bd576;hb=c35734b2a6f9b028edacd5813ff271728ce2a9e3;hp=4afc6d888c5a244769433b2aec58461dc6f280d1;hpb=c59372208a928828dd7d1cceaee78b48e5e03611;p=qemu diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 4afc6d8..5eb5b39 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -28,10 +28,13 @@ #include #include #include +#include +#include #include #include #include #include +#include #include #include #include @@ -42,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -69,7 +73,8 @@ //#define DEBUG -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \ + || defined(TARGET_M68K) /* 16 bit uid wrappers emulation */ #define USE_UID16 #endif @@ -79,133 +84,66 @@ #define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2]) -#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 +#undef _syscall6 -/* 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 _syscall0(type,name) \ +type name (void) \ +{ \ + return syscall(__NR_##name); \ +} -#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) \ +{ \ + return syscall(__NR_##name, arg1); \ } -#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) \ +{ \ + return syscall(__NR_##name, arg1, arg2); \ } -#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) \ +{ \ + return syscall(__NR_##name, arg1, arg2, arg3); \ } -#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) \ +{ \ + return syscall(__NR_##name, arg1, arg2, arg3, arg4); \ } -#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) \ +{ \ + return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \ } -#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); \ + +#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ +type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ +{ \ + return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \ } -#endif + #define __NR_sys_uname __NR_uname #define __NR_sys_getcwd1 __NR_getcwd #define __NR_sys_getdents __NR_getdents #define __NR_sys_getdents64 __NR_getdents64 #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo +#define __NR_sys_syslog __NR_syslog #if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) #define __NR__llseek __NR_lseek @@ -225,9 +163,13 @@ _syscall3(int, sys_getdents64, uint, fd, struct dirent64 *, dirp, uint, count); _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh); _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo) +_syscall3(int,sys_syslog,int,type,char*,bufp,int,len) #ifdef __NR_exit_group _syscall1(int,exit_group,int,error_code) #endif +#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address) +_syscall1(int,set_tid_address,int *,tidptr) +#endif extern int personality(int); extern int flock(int, int); @@ -514,7 +456,7 @@ static inline void target_to_host_cmsg(struct msghdr *msgh, 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) { + if (cmsg->cmsg_level != TARGET_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 { @@ -558,7 +500,7 @@ static inline void host_to_target_cmsg(struct target_msghdr *target_msgh, 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) { + if (cmsg->cmsg_level != TARGET_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 { @@ -620,38 +562,74 @@ static long do_setsockopt(int sockfd, int level, int optname, goto unimplemented; } break; - case SOL_SOCKET: + case TARGET_SOL_SOCKET: 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 TARGET_SO_DEBUG: + optname = SO_DEBUG; + break; + case TARGET_SO_REUSEADDR: + optname = SO_REUSEADDR; + break; + case TARGET_SO_TYPE: + optname = SO_TYPE; + break; + case TARGET_SO_ERROR: + optname = SO_ERROR; + break; + case TARGET_SO_DONTROUTE: + optname = SO_DONTROUTE; + break; + case TARGET_SO_BROADCAST: + optname = SO_BROADCAST; + break; + case TARGET_SO_SNDBUF: + optname = SO_SNDBUF; + break; + case TARGET_SO_RCVBUF: + optname = SO_RCVBUF; + break; + case TARGET_SO_KEEPALIVE: + optname = SO_KEEPALIVE; + break; + case TARGET_SO_OOBINLINE: + optname = SO_OOBINLINE; + break; + case TARGET_SO_NO_CHECK: + optname = SO_NO_CHECK; + break; + case TARGET_SO_PRIORITY: + optname = SO_PRIORITY; + break; #ifdef SO_BSDCOMPAT - case SO_BSDCOMPAT: -#endif - case SO_PASSCRED: - case SO_TIMESTAMP: - case SO_RCVLOWAT: - case SO_RCVTIMEO: - case SO_SNDTIMEO: - if (optlen < sizeof(uint32_t)) - return -EINVAL; - - val = tget32(optval); - ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); + case TARGET_SO_BSDCOMPAT: + optname = SO_BSDCOMPAT; + break; +#endif + case TARGET_SO_PASSCRED: + optname = SO_PASSCRED; + break; + case TARGET_SO_TIMESTAMP: + optname = SO_TIMESTAMP; + break; + case TARGET_SO_RCVLOWAT: + optname = SO_RCVLOWAT; + break; + case TARGET_SO_RCVTIMEO: + optname = SO_RCVTIMEO; + break; + case TARGET_SO_SNDTIMEO: + optname = SO_SNDTIMEO; + break; break; default: goto unimplemented; } + if (optlen < sizeof(uint32_t)) + return -EINVAL; + + val = tget32(optval); + ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val))); break; default: unimplemented: @@ -667,13 +645,14 @@ static long do_getsockopt(int sockfd, int level, int optname, int len, lv, val, ret; switch(level) { - case SOL_SOCKET: + case TARGET_SOL_SOCKET: + level = SOL_SOCKET; switch (optname) { - case SO_LINGER: - case SO_RCVTIMEO: - case SO_SNDTIMEO: - case SO_PEERCRED: - case SO_PEERNAME: + case TARGET_SO_LINGER: + case TARGET_SO_RCVTIMEO: + case TARGET_SO_SNDTIMEO: + case TARGET_SO_PEERCRED: + case TARGET_SO_PEERNAME: /* These don't just return a single integer */ goto unimplemented; default: @@ -779,6 +758,201 @@ static void unlock_iovec(struct iovec *vec, target_ulong target_addr, unlock_user (target_vec, target_addr, 0); } +static long do_socket(int domain, int type, int protocol) +{ +#if defined(TARGET_MIPS) + switch(type) { + case TARGET_SOCK_DGRAM: + type = SOCK_DGRAM; + break; + case TARGET_SOCK_STREAM: + type = SOCK_STREAM; + break; + case TARGET_SOCK_RAW: + type = SOCK_RAW; + break; + case TARGET_SOCK_RDM: + type = SOCK_RDM; + break; + case TARGET_SOCK_SEQPACKET: + type = SOCK_SEQPACKET; + break; + case TARGET_SOCK_PACKET: + type = SOCK_PACKET; + break; + } +#endif + return get_errno(socket(domain, type, protocol)); +} + +static long do_bind(int sockfd, target_ulong target_addr, + socklen_t addrlen) +{ + void *addr = alloca(addrlen); + + target_to_host_sockaddr(addr, target_addr, addrlen); + return get_errno(bind(sockfd, addr, addrlen)); +} + +static long do_connect(int sockfd, target_ulong target_addr, + socklen_t addrlen) +{ + void *addr = alloca(addrlen); + + target_to_host_sockaddr(addr, target_addr, addrlen); + return get_errno(connect(sockfd, addr, addrlen)); +} + +static long do_sendrecvmsg(int fd, target_ulong target_msg, + int flags, int send) +{ + long ret; + struct target_msghdr *msgp; + struct msghdr msg; + int count; + struct iovec *vec; + target_ulong target_vec; + + lock_user_struct(msgp, target_msg, 1); + if (msgp->msg_name) { + msg.msg_namelen = tswap32(msgp->msg_namelen); + msg.msg_name = alloca(msg.msg_namelen); + target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name), + msg.msg_namelen); + } else { + msg.msg_name = NULL; + msg.msg_namelen = 0; + } + 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); + vec = alloca(count * sizeof(struct iovec)); + target_vec = tswapl(msgp->msg_iov); + lock_iovec(vec, target_vec, count, send); + msg.msg_iovlen = count; + msg.msg_iov = vec; + + if (send) { + 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); + } + unlock_iovec(vec, target_vec, count, !send); + return ret; +} + +static long do_accept(int fd, target_ulong target_addr, + target_ulong target_addrlen) +{ + socklen_t addrlen = tget32(target_addrlen); + void *addr = alloca(addrlen); + long ret; + + ret = get_errno(accept(fd, addr, &addrlen)); + if (!is_error(ret)) { + host_to_target_sockaddr(target_addr, addr, addrlen); + tput32(target_addrlen, addrlen); + } + return ret; +} + +static long do_getpeername(int fd, target_ulong target_addr, + target_ulong target_addrlen) +{ + socklen_t addrlen = tget32(target_addrlen); + void *addr = alloca(addrlen); + long ret; + + ret = get_errno(getpeername(fd, addr, &addrlen)); + if (!is_error(ret)) { + host_to_target_sockaddr(target_addr, addr, addrlen); + tput32(target_addrlen, addrlen); + } + return ret; +} + +static long do_getsockname(int fd, target_ulong target_addr, + target_ulong target_addrlen) +{ + socklen_t addrlen = tget32(target_addrlen); + void *addr = alloca(addrlen); + long ret; + + ret = get_errno(getsockname(fd, addr, &addrlen)); + if (!is_error(ret)) { + host_to_target_sockaddr(target_addr, addr, addrlen); + tput32(target_addrlen, addrlen); + } + return ret; +} + +static long do_socketpair(int domain, int type, int protocol, + target_ulong target_tab) +{ + int tab[2]; + long ret; + + ret = get_errno(socketpair(domain, type, protocol, tab)); + if (!is_error(ret)) { + tput32(target_tab, tab[0]); + tput32(target_tab + 4, tab[1]); + } + return ret; +} + +static long do_sendto(int fd, target_ulong msg, size_t len, int flags, + target_ulong target_addr, socklen_t addrlen) +{ + void *addr; + void *host_msg; + long ret; + + host_msg = lock_user(msg, len, 1); + if (target_addr) { + addr = alloca(addrlen); + target_to_host_sockaddr(addr, target_addr, addrlen); + ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen)); + } else { + ret = get_errno(send(fd, host_msg, len, flags)); + } + unlock_user(host_msg, msg, 0); + return ret; +} + +static long do_recvfrom(int fd, target_ulong msg, size_t len, int flags, + target_ulong target_addr, target_ulong target_addrlen) +{ + socklen_t addrlen; + void *addr; + void *host_msg; + long ret; + + host_msg = lock_user(msg, len, 0); + if (target_addr) { + addrlen = tget32(target_addrlen); + addr = alloca(addrlen); + ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen)); + } else { + addr = NULL; /* To keep compiler quiet. */ + ret = get_errno(recv(fd, host_msg, len, flags)); + } + if (!is_error(ret)) { + if (target_addr) { + host_to_target_sockaddr(target_addr, addr, addrlen); + tput32(target_addrlen, addrlen); + } + unlock_user(host_msg, msg, len); + } else { + unlock_user(host_msg, msg, 0); + } + return ret; +} + static long do_socketcall(int num, target_ulong vptr) { long ret; @@ -790,8 +964,7 @@ static long do_socketcall(int num, target_ulong vptr) int domain = tgetl(vptr); int type = tgetl(vptr + n); int protocol = tgetl(vptr + 2 * n); - - ret = get_errno(socket(domain, type, protocol)); + ret = do_socket(domain, type, protocol); } break; case SOCKOP_bind: @@ -799,10 +972,7 @@ static long do_socketcall(int num, target_ulong vptr) int sockfd = tgetl(vptr); target_ulong target_addr = tgetl(vptr + n); socklen_t addrlen = tgetl(vptr + 2 * n); - void *addr = alloca(addrlen); - - target_to_host_sockaddr(addr, target_addr, addrlen); - ret = get_errno(bind(sockfd, addr, addrlen)); + ret = do_bind(sockfd, target_addr, addrlen); } break; case SOCKOP_connect: @@ -810,17 +980,13 @@ static long do_socketcall(int num, target_ulong vptr) int sockfd = tgetl(vptr); target_ulong target_addr = tgetl(vptr + n); socklen_t addrlen = tgetl(vptr + 2 * n); - void *addr = alloca(addrlen); - - target_to_host_sockaddr(addr, target_addr, addrlen); - ret = get_errno(connect(sockfd, addr, addrlen)); + ret = do_connect(sockfd, target_addr, addrlen); } break; case SOCKOP_listen: { int sockfd = tgetl(vptr); int backlog = tgetl(vptr + n); - ret = get_errno(listen(sockfd, backlog)); } break; @@ -829,14 +995,7 @@ static long do_socketcall(int num, target_ulong vptr) int sockfd = tgetl(vptr); target_ulong target_addr = tgetl(vptr + n); target_ulong target_addrlen = tgetl(vptr + 2 * n); - socklen_t addrlen = tget32(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); - tput32(target_addrlen, addrlen); - } + ret = do_accept(sockfd, target_addr, target_addrlen); } break; case SOCKOP_getsockname: @@ -844,14 +1003,7 @@ static long do_socketcall(int num, target_ulong vptr) int sockfd = tgetl(vptr); target_ulong target_addr = tgetl(vptr + n); target_ulong target_addrlen = tgetl(vptr + 2 * n); - socklen_t addrlen = tget32(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); - tput32(target_addrlen, addrlen); - } + ret = do_getsockname(sockfd, target_addr, target_addrlen); } break; case SOCKOP_getpeername: @@ -859,14 +1011,7 @@ static long do_socketcall(int num, target_ulong vptr) int sockfd = tgetl(vptr); target_ulong target_addr = tgetl(vptr + n); target_ulong target_addrlen = tgetl(vptr + 2 * n); - socklen_t addrlen = tget32(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); - tput32(target_addrlen, addrlen); - } + ret = do_getpeername(sockfd, target_addr, target_addrlen); } break; case SOCKOP_socketpair: @@ -874,14 +1019,8 @@ static long do_socketcall(int num, target_ulong vptr) int domain = tgetl(vptr); int type = tgetl(vptr + n); int protocol = tgetl(vptr + 2 * n); - target_ulong target_tab = tgetl(vptr + 3 * n); - int tab[2]; - - ret = get_errno(socketpair(domain, type, protocol, tab)); - if (!is_error(ret)) { - tput32(target_tab, tab[0]); - tput32(target_tab + 4, tab[1]); - } + target_ulong tab = tgetl(vptr + 3 * n); + ret = do_socketpair(domain, type, protocol, tab); } break; case SOCKOP_send: @@ -890,11 +1029,7 @@ static long do_socketcall(int num, target_ulong vptr) target_ulong msg = tgetl(vptr + n); size_t len = tgetl(vptr + 2 * n); int flags = tgetl(vptr + 3 * n); - void *host_msg; - - host_msg = lock_user(msg, len, 1); - ret = get_errno(send(sockfd, host_msg, len, flags)); - unlock_user(host_msg, msg, 0); + ret = do_sendto(sockfd, msg, len, flags, 0, 0); } break; case SOCKOP_recv: @@ -903,11 +1038,7 @@ static long do_socketcall(int num, target_ulong vptr) target_ulong msg = tgetl(vptr + n); size_t len = tgetl(vptr + 2 * n); int flags = tgetl(vptr + 3 * n); - void *host_msg; - - host_msg = lock_user(msg, len, 0); - ret = get_errno(recv(sockfd, host_msg, len, flags)); - unlock_user(host_msg, msg, ret); + ret = do_recvfrom(sockfd, msg, len, flags, 0, 0); } break; case SOCKOP_sendto: @@ -916,15 +1047,9 @@ static long do_socketcall(int num, target_ulong vptr) target_ulong msg = tgetl(vptr + n); size_t len = tgetl(vptr + 2 * n); int flags = tgetl(vptr + 3 * n); - target_ulong target_addr = tgetl(vptr + 4 * n); + target_ulong addr = tgetl(vptr + 4 * n); socklen_t addrlen = tgetl(vptr + 5 * n); - void *addr = alloca(addrlen); - void *host_msg; - - host_msg = lock_user(msg, len, 1); - target_to_host_sockaddr(addr, target_addr, addrlen); - ret = get_errno(sendto(sockfd, host_msg, len, flags, addr, addrlen)); - unlock_user(host_msg, msg, 0); + ret = do_sendto(sockfd, msg, len, flags, addr, addrlen); } break; case SOCKOP_recvfrom: @@ -933,21 +1058,9 @@ static long do_socketcall(int num, target_ulong vptr) target_ulong msg = tgetl(vptr + n); size_t len = tgetl(vptr + 2 * n); int flags = tgetl(vptr + 3 * n); - target_ulong target_addr = tgetl(vptr + 4 * n); - target_ulong target_addrlen = tgetl(vptr + 5 * n); - socklen_t addrlen = tget32(target_addrlen); - void *addr = alloca(addrlen); - void *host_msg; - - host_msg = lock_user(msg, len, 0); - ret = get_errno(recvfrom(sockfd, host_msg, len, flags, addr, &addrlen)); - if (!is_error(ret)) { - host_to_target_sockaddr(target_addr, addr, addrlen); - tput32(target_addrlen, addrlen); - unlock_user(host_msg, msg, len); - } else { - unlock_user(host_msg, msg, 0); - } + target_ulong addr = tgetl(vptr + 4 * n); + target_ulong addrlen = tgetl(vptr + 5 * n); + ret = do_recvfrom(sockfd, msg, len, flags, addr, addrlen); } break; case SOCKOP_shutdown: @@ -963,46 +1076,14 @@ static long do_socketcall(int num, target_ulong vptr) { int fd; target_ulong target_msg; - struct target_msghdr *msgp; - struct msghdr msg; - int flags, count; - struct iovec *vec; - target_ulong target_vec; - int send = (num == SOCKOP_sendmsg); - - target_msg = tgetl(vptr + n); - lock_user_struct(msgp, target_msg, 1); - if (msgp->msg_name) { - msg.msg_namelen = tswap32(msgp->msg_namelen); - msg.msg_name = alloca(msg.msg_namelen); - target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name), - msg.msg_namelen); - } else { - msg.msg_name = NULL; - msg.msg_namelen = 0; - } - 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); - vec = alloca(count * sizeof(struct iovec)); - target_vec = tswapl(msgp->msg_iov); - lock_iovec(vec, target_vec, count, send); - msg.msg_iovlen = count; - msg.msg_iov = vec; + int flags; fd = tgetl(vptr); + target_msg = tgetl(vptr + n); flags = tgetl(vptr + 2 * n); - if (send) { - 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); - } - unlock_iovec(vec, target_vec, count, !send); + + ret = do_sendrecvmsg(fd, target_msg, flags, + (num == SOCKOP_sendmsg)); } break; case SOCKOP_setsockopt: @@ -1035,7 +1116,6 @@ static long do_socketcall(int num, target_ulong vptr) return ret; } - #define N_SHM_REGIONS 32 static struct shm_region { @@ -1043,6 +1123,12 @@ static struct shm_region { uint32_t size; } shm_regions[N_SHM_REGIONS]; +union semun { + int val; + struct senid_ds *buf; + unsigned short *array; +}; + /* ??? This only works with linear mappings. */ static long do_ipc(long call, long first, long second, long third, long ptr, long fifth) @@ -1057,6 +1143,52 @@ static long do_ipc(long call, long first, long second, long third, call &= 0xffff; switch (call) { + case IPCOP_semop: + ret = get_errno(semop(first,(struct sembuf *) ptr, second)); + break; + + case IPCOP_semget: + ret = get_errno(semget(first, second, third)); + break; + + case IPCOP_semctl: + ret = get_errno(semctl(first, second, third, ((union semun*)ptr)->val)); + + break; + + case IPCOP_semtimedop: + gemu_log("Unsupported ipc call: %ld (version %d)\n", call, version); + ret = -ENOSYS; + break; + + case IPCOP_msgget: + ret = get_errno(msgget(first, second)); + break; + + case IPCOP_msgsnd: + ret = get_errno(msgsnd(first, (struct msgbuf *) ptr, second, third)); + break; + + case IPCOP_msgctl: + ret = get_errno(msgctl(first, second, (struct msqid_ds *) ptr)); + break; + + case IPCOP_msgrcv: + { + struct ipc_kludge + { + void *__unbounded msgp; + long int msgtyp; + }; + + struct ipc_kludge *foo = (struct ipc_kludge *) ptr; + struct msgbuf *msgp = (struct msgbuf *) foo->msgp; + + ret = get_errno(msgrcv(first, msgp, second, 0, third)); + + } + break; + case IPCOP_shmat: /* SHM_* flags are the same on all linux platforms */ ret = get_errno((long) shmat(first, (void *) ptr, second)); @@ -1593,8 +1725,7 @@ int do_fork(CPUState *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_init(); - memcpy(new_env, env, sizeof(CPUState)); + new_env = cpu_copy(env); #if defined(TARGET_I386) if (!newsp) newsp = env->regs[R_ESP]; @@ -1606,7 +1737,18 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp) new_env->regs[13] = newsp; new_env->regs[0] = 0; #elif defined(TARGET_SPARC) + if (!newsp) + newsp = env->regwptr[22]; + new_env->regwptr[22] = newsp; + new_env->regwptr[0] = 0; + /* XXXXX */ printf ("HELPME: %s:%d\n", __FILE__, __LINE__); +#elif defined(TARGET_M68K) + if (!newsp) + newsp = env->aregs[7]; + new_env->aregs[7] = newsp; + new_env->dregs[0] = 0; + /* ??? is this sufficient? */ #elif defined(TARGET_MIPS) printf ("HELPME: %s:%d\n", __FILE__, __LINE__); #elif defined(TARGET_PPC) @@ -1645,6 +1787,8 @@ static long do_fcntl(int fd, int cmd, target_ulong arg) { struct flock fl; struct target_flock *target_fl; + struct flock64 fl64; + struct target_flock64 *target_fl64; long ret; switch(cmd) { @@ -1674,10 +1818,27 @@ static long do_fcntl(int fd, int cmd, target_ulong arg) break; case TARGET_F_GETLK64: + ret = fcntl(fd, cmd >> 1, &fl64); + if (ret == 0) { + lock_user_struct(target_fl64, arg, 0); + target_fl64->l_type = tswap16(fl64.l_type) >> 1; + target_fl64->l_whence = tswap16(fl64.l_whence); + target_fl64->l_start = tswapl(fl64.l_start); + target_fl64->l_len = tswapl(fl64.l_len); + target_fl64->l_pid = tswapl(fl64.l_pid); + unlock_user_struct(target_fl64, arg, 1); + } + break; case TARGET_F_SETLK64: case TARGET_F_SETLKW64: - ret = -1; - errno = EINVAL; + lock_user_struct(target_fl64, arg, 1); + fl64.l_type = tswap16(target_fl64->l_type) >> 1; + fl64.l_whence = tswap16(target_fl64->l_whence); + fl64.l_start = tswapl(target_fl64->l_start); + fl64.l_len = tswapl(target_fl64->l_len); + fl64.l_pid = tswap16(target_fl64->l_pid); + unlock_user_struct(target_fl64, arg, 0); + ret = fcntl(fd, cmd >> 1, &fl64); break; case F_GETFL: @@ -2006,8 +2167,18 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(getpid()); break; case TARGET_NR_mount: - /* need to look at the data field */ - goto unimplemented; + { + /* need to look at the data field */ + void *p2, *p3; + p = lock_user_string(arg1); + p2 = lock_user_string(arg2); + p3 = lock_user_string(arg3); + ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, (const void *)arg5)); + unlock_user(p, arg1, 0); + unlock_user(p2, arg2, 0); + unlock_user(p3, arg3, 0); + break; + } case TARGET_NR_umount: p = lock_user_string(arg1); ret = get_errno(umount(p)); @@ -2208,6 +2379,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; case TARGET_NR_sigaction: { + #if !defined(TARGET_MIPS) struct target_old_sigaction *old_act; struct target_sigaction act, oact, *pact; if (arg2) { @@ -2230,6 +2402,33 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, old_act->sa_restorer = oact.sa_restorer; unlock_user_struct(old_act, arg3, 1); } + #else + struct target_sigaction act, oact, *pact, *old_act; + + if (arg2) { + lock_user_struct(old_act, arg2, 1); + act._sa_handler = old_act->_sa_handler; + target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]); + act.sa_flags = old_act->sa_flags; + 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) { + lock_user_struct(old_act, arg3, 0); + old_act->_sa_handler = oact._sa_handler; + old_act->sa_flags = oact.sa_flags; + old_act->sa_mask.sig[0] = oact.sa_mask.sig[0]; + old_act->sa_mask.sig[1] = 0; + old_act->sa_mask.sig[2] = 0; + old_act->sa_mask.sig[3] = 0; + unlock_user_struct(old_act, arg3, 1); + } + #endif } break; case TARGET_NR_rt_sigaction: @@ -2538,7 +2737,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_readdir: goto unimplemented; case TARGET_NR_mmap: -#if defined(TARGET_I386) || defined(TARGET_ARM) +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_M68K) { target_ulong *v; target_ulong v1, v2, v3, v4, v5, v6; @@ -2563,7 +2762,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; #ifdef TARGET_NR_mmap2 case TARGET_NR_mmap2: -#if defined(TARGET_SPARC) +#if defined(TARGET_SPARC) || defined(TARGET_MIPS) #define MMAP_SHIFT 12 #else #define MMAP_SHIFT TARGET_PAGE_BITS @@ -2679,8 +2878,99 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_socketcall: ret = do_socketcall(arg1, arg2); break; + +#ifdef TARGET_NR_accept + case TARGET_NR_accept: + ret = do_accept(arg1, arg2, arg3); + break; +#endif +#ifdef TARGET_NR_bind + case TARGET_NR_bind: + ret = do_bind(arg1, arg2, arg3); + break; +#endif +#ifdef TARGET_NR_connect + case TARGET_NR_connect: + ret = do_connect(arg1, arg2, arg3); + break; +#endif +#ifdef TARGET_NR_getpeername + case TARGET_NR_getpeername: + ret = do_getpeername(arg1, arg2, arg3); + break; +#endif +#ifdef TARGET_NR_getsockname + case TARGET_NR_getsockname: + ret = do_getsockname(arg1, arg2, arg3); + break; +#endif +#ifdef TARGET_NR_getsockopt + case TARGET_NR_getsockopt: + ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5); + break; +#endif +#ifdef TARGET_NR_listen + case TARGET_NR_listen: + ret = get_errno(listen(arg1, arg2)); + break; +#endif +#ifdef TARGET_NR_recv + case TARGET_NR_recv: + ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0); + break; +#endif +#ifdef TARGET_NR_recvfrom + case TARGET_NR_recvfrom: + ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6); + break; +#endif +#ifdef TARGET_NR_recvmsg + case TARGET_NR_recvmsg: + ret = do_sendrecvmsg(arg1, arg2, arg3, 0); + break; +#endif +#ifdef TARGET_NR_send + case TARGET_NR_send: + ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0); + break; +#endif +#ifdef TARGET_NR_sendmsg + case TARGET_NR_sendmsg: + ret = do_sendrecvmsg(arg1, arg2, arg3, 1); + break; +#endif +#ifdef TARGET_NR_sendto + case TARGET_NR_sendto: + ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6); + break; +#endif +#ifdef TARGET_NR_shutdown + case TARGET_NR_shutdown: + ret = get_errno(shutdown(arg1, arg2)); + break; +#endif +#ifdef TARGET_NR_socket + case TARGET_NR_socket: + ret = do_socket(arg1, arg2, arg3); + break; +#endif +#ifdef TARGET_NR_socketpair + case TARGET_NR_socketpair: + ret = do_socketpair(arg1, arg2, arg3, arg4); + break; +#endif +#ifdef TARGET_NR_setsockopt + case TARGET_NR_setsockopt: + ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5); + break; +#endif + case TARGET_NR_syslog: - goto unimplemented; + p = lock_user_string(arg2); + ret = get_errno(sys_syslog((int)arg1, p, (int)arg3)); + unlock_user(p, arg2, 0); + break; + case TARGET_NR_setitimer: { struct itimerval value, ovalue, *pvalue; @@ -2736,7 +3026,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, lock_user_struct(target_st, arg2, 0); target_st->st_dev = tswap16(st.st_dev); target_st->st_ino = tswapl(st.st_ino); -#if defined(TARGET_PPC) +#if defined(TARGET_PPC) || defined(TARGET_MIPS) target_st->st_mode = tswapl(st.st_mode); /* XXX: check this */ target_st->st_uid = tswap32(st.st_uid); target_st->st_gid = tswap32(st.st_gid); @@ -3149,7 +3439,21 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_nfsservctl: goto unimplemented; case TARGET_NR_prctl: - goto unimplemented; + switch (arg1) + { + case PR_GET_PDEATHSIG: + { + int deathsig; + ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5)); + if (!is_error(ret) && arg2) + tput32(arg2, deathsig); + } + break; + default: + ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5)); + break; + } + break; #ifdef TARGET_NR_pread case TARGET_NR_pread: page_unprotect_range(arg2, arg3); @@ -3632,6 +3936,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; } #endif +#ifdef TARGET_NR_cacheflush + case TARGET_NR_cacheflush: + /* self-modifying code is handled automatically, so nothing needed */ + ret = 0; + break; +#endif #ifdef TARGET_NR_security case TARGET_NR_security: goto unimplemented; @@ -3663,13 +3973,56 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #endif #ifdef TARGET_NR_set_thread_area case TARGET_NR_set_thread_area: +#ifdef TARGET_MIPS + ((CPUMIPSState *) cpu_env)->tls_value = arg1; + ret = 0; + break; +#else + goto unimplemented_nowarn; +#endif +#endif +#ifdef TARGET_NR_get_thread_area case TARGET_NR_get_thread_area: goto unimplemented_nowarn; #endif +#ifdef TARGET_NR_getdomainname + case TARGET_NR_getdomainname: + goto unimplemented_nowarn; +#endif + +#ifdef TARGET_NR_clock_gettime + case TARGET_NR_clock_gettime: + { + struct timespec ts; + ret = get_errno(clock_gettime(arg1, &ts)); + if (!is_error(ret)) { + host_to_target_timespec(arg2, &ts); + } + break; + } +#endif +#ifdef TARGET_NR_clock_getres + case TARGET_NR_clock_getres: + { + struct timespec ts; + ret = get_errno(clock_getres(arg1, &ts)); + if (!is_error(ret)) { + host_to_target_timespec(arg2, &ts); + } + break; + } +#endif + +#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address) + case TARGET_NR_set_tid_address: + ret = get_errno(set_tid_address((int *) arg1)); + break; +#endif + default: unimplemented: gemu_log("qemu: Unsupported syscall: %d\n", num); -#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_set_thread_area) +#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_get_thread_area) || defined(TARGET_NR_getdomainname) unimplemented_nowarn: #endif ret = -ENOSYS;