update
[qemu] / linux-user / syscall.c
index ac7a111..b226429 100644 (file)
 #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);
-
 #define __NR_sys_uname __NR_uname
 #define __NR_sys_getcwd1 __NR_getcwd
 #define __NR_sys_statfs __NR_statfs
@@ -215,6 +210,29 @@ static inline void host_to_target_fds(target_long *target_fds,
 #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)
 {
@@ -679,8 +697,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];
@@ -692,7 +710,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"
@@ -935,7 +953,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;
@@ -1024,7 +1054,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));
@@ -1052,28 +1082,28 @@ int do_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecount
     return ret;
 }
 
+#endif /* defined(TARGET_I386) */
+
 /* this stack is the equivalent of the kernel stack associated with a
    thread/process */
 #define NEW_STACK_SIZE 8192
 
 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;
@@ -1082,10 +1112,21 @@ 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;
 #ifdef __ia64__
         ret = clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
@@ -1101,7 +1142,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)
@@ -1110,11 +1192,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, 
@@ -1137,6 +1251,7 @@ 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:
@@ -1342,42 +1457,8 @@ 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:
-    {
-       struct flock fl;
-       struct target_flock *target_fl = (void *)arg3;
-
-        switch(arg2) {
-        case TARGET_F_GETLK:
-            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 = 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 = get_errno(fcntl(arg1, arg2, &fl));
-           break;
-
-       case TARGET_F_GETLK64:
-       case TARGET_F_SETLK64:
-       case TARGET_F_SETLKW64:
-            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;
     case TARGET_NR_setpgid:
@@ -1626,7 +1707,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;
@@ -1703,7 +1792,9 @@ 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(target_mmap(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
@@ -1712,7 +1803,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
 #else
     case TARGET_NR_mmap:
 #endif
-        ret = get_errno(target_mmap(arg1, arg2, arg3, arg4, arg5, arg6));
+        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(target_munmap(arg1, arg2));
@@ -1876,24 +1970,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);
                 }
             }
         }
@@ -1974,7 +2051,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;
@@ -1997,6 +2114,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
                 }
             }
         }
+#endif
         break;
     case TARGET_NR_getdents64:
         {
@@ -2191,9 +2309,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;
@@ -2369,7 +2490,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
             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;