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 41 #include <sys/uio.h>
42 42 #include <sys/poll.h>
43 43 #include <sys/times.h>
  44 +#include <sys/shm.h>
44 45 #include <utime.h>
45 46 //#include <sys/user.h>
  47 +#include <netinet/ip.h>
46 48 #include <netinet/tcp.h>
47 49  
48 50 #define termios host_termios
... ... @@ -325,7 +327,7 @@ static inline void host_to_target_fds(target_long *target_fds,
325 327 target_long v;
326 328  
327 329 if (target_fds) {
328   - nw = n / TARGET_LONG_BITS;
  330 + nw = (n + TARGET_LONG_BITS - 1) / TARGET_LONG_BITS;
329 331 k = 0;
330 332 for(i = 0;i < nw; i++) {
331 333 v = 0;
... ... @@ -530,61 +532,116 @@ static inline void host_to_target_cmsg(struct target_msghdr *target_msgh,
530 532 static long do_setsockopt(int sockfd, int level, int optname,
531 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 539 /* TCP options all take an 'int' value. */
535   - int val;
536   -
537 540 if (optlen < sizeof(uint32_t))
538 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 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 603 static long do_getsockopt(int sockfd, int level, int optname,
584 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 647 static long do_socketcall(int num, int32_t *vptr)
... ... @@ -807,12 +864,9 @@ static long do_socketcall(int num, int32_t *vptr)
807 864 int level = tswap32(vptr[1]);
808 865 int optname = tswap32(vptr[2]);
809 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 871 break;
818 872 default:
... ... @@ -823,6 +877,92 @@ static long do_socketcall(int num, int32_t *vptr)
823 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 966 /* kernel structure types definitions */
827 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 2345 case TARGET_NR_sysinfo:
2206 2346 goto unimplemented;
2207 2347 case TARGET_NR_ipc:
2208   - goto unimplemented;
  2348 + ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
  2349 + break;
2209 2350 case TARGET_NR_fsync:
2210 2351 ret = get_errno(fsync(arg1));
2211 2352 break;
... ...
linux-user/syscall_defs.h
... ... @@ -24,6 +24,19 @@
24 24 #define SOCKOP_sendmsg 16
25 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 41 * The following is for compatibility across the various Linux
29 42 * platforms. The i386 ioctl numbering scheme doesn't really enforce
... ...