Commit 8853f86e1da70e79464aa3329f7b84a27a199bad

Authored by bellard
1 parent e374bfa3

shm support, more setsockopt and getsockopt calls, fds fix (initial patch by Paul McKerras)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@638 c046a42c-6fe2-441c-8c8c-71466251a162
linux-user/syscall.c
@@ -41,8 +41,10 @@ @@ -41,8 +41,10 @@
41 #include <sys/uio.h> 41 #include <sys/uio.h>
42 #include <sys/poll.h> 42 #include <sys/poll.h>
43 #include <sys/times.h> 43 #include <sys/times.h>
  44 +#include <sys/shm.h>
44 #include <utime.h> 45 #include <utime.h>
45 //#include <sys/user.h> 46 //#include <sys/user.h>
  47 +#include <netinet/ip.h>
46 #include <netinet/tcp.h> 48 #include <netinet/tcp.h>
47 49
48 #define termios host_termios 50 #define termios host_termios
@@ -325,7 +327,7 @@ static inline void host_to_target_fds(target_long *target_fds, @@ -325,7 +327,7 @@ static inline void host_to_target_fds(target_long *target_fds,
325 target_long v; 327 target_long v;
326 328
327 if (target_fds) { 329 if (target_fds) {
328 - nw = n / TARGET_LONG_BITS; 330 + nw = (n + TARGET_LONG_BITS - 1) / TARGET_LONG_BITS;
329 k = 0; 331 k = 0;
330 for(i = 0;i < nw; i++) { 332 for(i = 0;i < nw; i++) {
331 v = 0; 333 v = 0;
@@ -530,61 +532,116 @@ static inline void host_to_target_cmsg(struct target_msghdr *target_msgh, @@ -530,61 +532,116 @@ static inline void host_to_target_cmsg(struct target_msghdr *target_msgh,
530 static long do_setsockopt(int sockfd, int level, int optname, 532 static long do_setsockopt(int sockfd, int level, int optname,
531 void *optval, socklen_t optlen) 533 void *optval, socklen_t optlen)
532 { 534 {
533 - if (level == SOL_TCP) { 535 + int val, ret;
  536 +
  537 + switch(level) {
  538 + case SOL_TCP:
534 /* TCP options all take an 'int' value. */ 539 /* TCP options all take an 'int' value. */
535 - int val;  
536 -  
537 if (optlen < sizeof(uint32_t)) 540 if (optlen < sizeof(uint32_t))
538 return -EINVAL; 541 return -EINVAL;
539 -  
540 - val = tswap32(*(uint32_t *)optval);  
541 - return get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));  
542 - }  
543 -  
544 - else if (level != SOL_SOCKET) {  
545 - gemu_log("Unsupported setsockopt level: %d\n", level);  
546 - return -ENOSYS;  
547 - }  
548 -  
549 - switch (optname) {  
550 - /* Options with 'int' argument. */  
551 - case SO_DEBUG:  
552 - case SO_REUSEADDR:  
553 - case SO_TYPE:  
554 - case SO_ERROR:  
555 - case SO_DONTROUTE:  
556 - case SO_BROADCAST:  
557 - case SO_SNDBUF:  
558 - case SO_RCVBUF:  
559 - case SO_KEEPALIVE:  
560 - case SO_OOBINLINE:  
561 - case SO_NO_CHECK:  
562 - case SO_PRIORITY:  
563 - case SO_BSDCOMPAT:  
564 - case SO_PASSCRED:  
565 - case SO_TIMESTAMP:  
566 - case SO_RCVLOWAT:  
567 - case SO_RCVTIMEO:  
568 - case SO_SNDTIMEO:  
569 - {  
570 - int val;  
571 - if (optlen < sizeof(uint32_t))  
572 - return -EINVAL;  
573 - val = tswap32(*(uint32_t *)optval);  
574 - return get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));  
575 - }  
576 - 542 +
  543 + if (get_user(val, (uint32_t *)optval))
  544 + return -EFAULT;
  545 + ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
  546 + break;
  547 + case SOL_IP:
  548 + switch(optname) {
  549 + case IP_HDRINCL:
  550 + val = 0;
  551 + if (optlen >= sizeof(uint32_t)) {
  552 + if (get_user(val, (uint32_t *)optval))
  553 + return -EFAULT;
  554 + } else if (optlen >= 1) {
  555 + if (get_user(val, (uint8_t *)optval))
  556 + return -EFAULT;
  557 + }
  558 + ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
  559 + break;
  560 + default:
  561 + goto unimplemented;
  562 + }
  563 + break;
  564 + case SOL_SOCKET:
  565 + switch (optname) {
  566 + /* Options with 'int' argument. */
  567 + case SO_DEBUG:
  568 + case SO_REUSEADDR:
  569 + case SO_TYPE:
  570 + case SO_ERROR:
  571 + case SO_DONTROUTE:
  572 + case SO_BROADCAST:
  573 + case SO_SNDBUF:
  574 + case SO_RCVBUF:
  575 + case SO_KEEPALIVE:
  576 + case SO_OOBINLINE:
  577 + case SO_NO_CHECK:
  578 + case SO_PRIORITY:
  579 + case SO_BSDCOMPAT:
  580 + case SO_PASSCRED:
  581 + case SO_TIMESTAMP:
  582 + case SO_RCVLOWAT:
  583 + case SO_RCVTIMEO:
  584 + case SO_SNDTIMEO:
  585 + if (optlen < sizeof(uint32_t))
  586 + return -EINVAL;
  587 + if (get_user(val, (uint32_t *)optval))
  588 + return -EFAULT;
  589 + ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
  590 + break;
  591 + default:
  592 + goto unimplemented;
  593 + }
  594 + break;
577 default: 595 default:
578 - gemu_log("Unsupported setsockopt SOL_SOCKET option: %d\n", optname);  
579 - return -ENOSYS; 596 + unimplemented:
  597 + gemu_log("Unsupported setsockopt level=%d optname=%d \n", level, optname);
  598 + ret = -ENOSYS;
580 } 599 }
  600 + return ret;
581 } 601 }
582 602
583 static long do_getsockopt(int sockfd, int level, int optname, 603 static long do_getsockopt(int sockfd, int level, int optname,
584 void *optval, socklen_t *optlen) 604 void *optval, socklen_t *optlen)
585 { 605 {
586 - gemu_log("getsockopt not yet supported\n");  
587 - return -ENOSYS; 606 + int len, lv, val, ret;
  607 +
  608 + switch(level) {
  609 + case SOL_SOCKET:
  610 + switch (optname) {
  611 + case SO_LINGER:
  612 + case SO_RCVTIMEO:
  613 + case SO_SNDTIMEO:
  614 + case SO_PEERCRED:
  615 + case SO_PEERNAME:
  616 + /* These don't just return a single integer */
  617 + goto unimplemented;
  618 + default:
  619 + if (get_user(len, optlen))
  620 + return -EFAULT;
  621 + if (len < 0)
  622 + return -EINVAL;
  623 + lv = sizeof(int);
  624 + ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
  625 + if (ret < 0)
  626 + return ret;
  627 + val = tswap32(val);
  628 + if (len > lv)
  629 + len = lv;
  630 + if (copy_to_user(optval, &val, len))
  631 + return -EFAULT;
  632 + if (put_user(len, optlen))
  633 + return -EFAULT;
  634 + break;
  635 + }
  636 + break;
  637 + default:
  638 + unimplemented:
  639 + gemu_log("getsockopt level=%d optname=%d not yet supported\n",
  640 + level, optname);
  641 + ret = -ENOSYS;
  642 + break;
  643 + }
  644 + return ret;
588 } 645 }
589 646
590 static long do_socketcall(int num, int32_t *vptr) 647 static long do_socketcall(int num, int32_t *vptr)
@@ -807,12 +864,9 @@ static long do_socketcall(int num, int32_t *vptr) @@ -807,12 +864,9 @@ static long do_socketcall(int num, int32_t *vptr)
807 int level = tswap32(vptr[1]); 864 int level = tswap32(vptr[1]);
808 int optname = tswap32(vptr[2]); 865 int optname = tswap32(vptr[2]);
809 void *optval = (void *)tswap32(vptr[3]); 866 void *optval = (void *)tswap32(vptr[3]);
810 - uint32_t *target_len = (void *)tswap32(vptr[4]);  
811 - socklen_t optlen = tswap32(*target_len); 867 + uint32_t *poptlen = (void *)tswap32(vptr[4]);
812 868
813 - ret = do_getsockopt(sockfd, level, optname, optval, &optlen);  
814 - if (!is_error(ret))  
815 - *target_len = tswap32(optlen); 869 + ret = do_getsockopt(sockfd, level, optname, optval, poptlen);
816 } 870 }
817 break; 871 break;
818 default: 872 default:
@@ -823,6 +877,92 @@ static long do_socketcall(int num, int32_t *vptr) @@ -823,6 +877,92 @@ static long do_socketcall(int num, int32_t *vptr)
823 return ret; 877 return ret;
824 } 878 }
825 879
  880 +
  881 +#define N_SHM_REGIONS 32
  882 +
  883 +static struct shm_region {
  884 + uint32_t start;
  885 + uint32_t size;
  886 +} shm_regions[N_SHM_REGIONS];
  887 +
  888 +static long do_ipc(long call, long first, long second, long third,
  889 + long ptr, long fifth)
  890 +{
  891 + int version;
  892 + long ret = 0;
  893 + unsigned long raddr;
  894 + struct shmid_ds shm_info;
  895 + int i;
  896 +
  897 + version = call >> 16;
  898 + call &= 0xffff;
  899 +
  900 + switch (call) {
  901 + case IPCOP_shmat:
  902 + /* SHM_* flags are the same on all linux platforms */
  903 + ret = get_errno((long) shmat(first, (void *) ptr, second));
  904 + if (is_error(ret))
  905 + break;
  906 + raddr = ret;
  907 + /* find out the length of the shared memory segment */
  908 +
  909 + ret = get_errno(shmctl(first, IPC_STAT, &shm_info));
  910 + if (is_error(ret)) {
  911 + /* can't get length, bail out */
  912 + shmdt((void *) raddr);
  913 + break;
  914 + }
  915 + page_set_flags(raddr, raddr + shm_info.shm_segsz,
  916 + PAGE_VALID | PAGE_READ |
  917 + ((second & SHM_RDONLY)? 0: PAGE_WRITE));
  918 + for (i = 0; i < N_SHM_REGIONS; ++i) {
  919 + if (shm_regions[i].start == 0) {
  920 + shm_regions[i].start = raddr;
  921 + shm_regions[i].size = shm_info.shm_segsz;
  922 + break;
  923 + }
  924 + }
  925 + if (put_user(raddr, (uint32_t *)third))
  926 + return -EFAULT;
  927 + ret = 0;
  928 + break;
  929 + case IPCOP_shmdt:
  930 + for (i = 0; i < N_SHM_REGIONS; ++i) {
  931 + if (shm_regions[i].start == ptr) {
  932 + shm_regions[i].start = 0;
  933 + page_set_flags(ptr, shm_regions[i].size, 0);
  934 + break;
  935 + }
  936 + }
  937 + ret = get_errno(shmdt((void *) ptr));
  938 + break;
  939 +
  940 + case IPCOP_shmget:
  941 + /* IPC_* flag values are the same on all linux platforms */
  942 + ret = get_errno(shmget(first, second, third));
  943 + break;
  944 +
  945 + /* IPC_* and SHM_* command values are the same on all linux platforms */
  946 + case IPCOP_shmctl:
  947 + switch(second) {
  948 + case IPC_RMID:
  949 + case SHM_LOCK:
  950 + case SHM_UNLOCK:
  951 + ret = get_errno(shmctl(first, second, NULL));
  952 + break;
  953 + default:
  954 + goto unimplemented;
  955 + }
  956 + break;
  957 + default:
  958 + unimplemented:
  959 + gemu_log("Unsupported ipc call: %ld (version %d)\n", call, version);
  960 + ret = -ENOSYS;
  961 + break;
  962 + }
  963 + return ret;
  964 +}
  965 +
826 /* kernel structure types definitions */ 966 /* kernel structure types definitions */
827 #define IFNAMSIZ 16 967 #define IFNAMSIZ 16
828 968
@@ -2205,7 +2345,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, @@ -2205,7 +2345,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
2205 case TARGET_NR_sysinfo: 2345 case TARGET_NR_sysinfo:
2206 goto unimplemented; 2346 goto unimplemented;
2207 case TARGET_NR_ipc: 2347 case TARGET_NR_ipc:
2208 - goto unimplemented; 2348 + ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
  2349 + break;
2209 case TARGET_NR_fsync: 2350 case TARGET_NR_fsync:
2210 ret = get_errno(fsync(arg1)); 2351 ret = get_errno(fsync(arg1));
2211 break; 2352 break;
linux-user/syscall_defs.h
@@ -24,6 +24,19 @@ @@ -24,6 +24,19 @@
24 #define SOCKOP_sendmsg 16 24 #define SOCKOP_sendmsg 16
25 #define SOCKOP_recvmsg 17 25 #define SOCKOP_recvmsg 17
26 26
  27 +#define IPCOP_semop 1
  28 +#define IPCOP_semget 2
  29 +#define IPCOP_semctl 3
  30 +#define IPCOP_semtimedop 4
  31 +#define IPCOP_msgsnd 11
  32 +#define IPCOP_msgrcv 12
  33 +#define IPCOP_msgget 13
  34 +#define IPCOP_msgctl 14
  35 +#define IPCOP_shmat 21
  36 +#define IPCOP_shmdt 22
  37 +#define IPCOP_shmget 23
  38 +#define IPCOP_shmctl 24
  39 +
27 /* 40 /*
28 * The following is for compatibility across the various Linux 41 * The following is for compatibility across the various Linux
29 * platforms. The i386 ioctl numbering scheme doesn't really enforce 42 * platforms. The i386 ioctl numbering scheme doesn't really enforce