PowerPC merge (Jocelyn Mayer)
[qemu] / linux-user / syscall.c
index d218009..52e1c6b 100644 (file)
 
 //#define DEBUG
 
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
+/* 16 bit uid wrappers emulation */
+#define USE_UID16
+#endif
+
 //#include <linux/msdos_fs.h>
 #define        VFAT_IOCTL_READDIR_BOTH         _IOR('r', 1, struct dirent [2])
 #define        VFAT_IOCTL_READDIR_SHORT        _IOR('r', 2, struct dirent [2])
@@ -234,6 +239,27 @@ extern int setresgid(gid_t, gid_t, gid_t);
 extern int getresgid(gid_t *, gid_t *, gid_t *);
 extern int setgroups(int, gid_t *);
 
+#define put_user(x,ptr)\
+({\
+    int size = sizeof(*ptr);\
+    switch(size) {\
+    case 1:\
+        stb(ptr, (typeof(*ptr))(x));\
+        break;\
+    case 2:\
+        stw(ptr, (typeof(*ptr))(x));\
+        break;\
+    case 4:\
+        stl(ptr, (typeof(*ptr))(x));\
+        break;\
+    case 8:\
+        stq(ptr, (typeof(*ptr))(x));\
+        break;\
+    default:\
+        abort();\
+    }\
+    0;\
+})
 static inline long get_errno(long ret)
 {
     if (ret == -1)
@@ -1104,6 +1130,24 @@ static bitmask_transtbl mmap_flags_tbl[] = {
        { 0, 0, 0, 0 }
 };
 
+static bitmask_transtbl fcntl_flags_tbl[] = {
+       { TARGET_O_ACCMODE,   TARGET_O_WRONLY,    O_ACCMODE,   O_WRONLY,    },
+       { TARGET_O_ACCMODE,   TARGET_O_RDWR,      O_ACCMODE,   O_RDWR,      },
+       { TARGET_O_CREAT,     TARGET_O_CREAT,     O_CREAT,     O_CREAT,     },
+       { TARGET_O_EXCL,      TARGET_O_EXCL,      O_EXCL,      O_EXCL,      },
+       { TARGET_O_NOCTTY,    TARGET_O_NOCTTY,    O_NOCTTY,    O_NOCTTY,    },
+       { TARGET_O_TRUNC,     TARGET_O_TRUNC,     O_TRUNC,     O_TRUNC,     },
+       { TARGET_O_APPEND,    TARGET_O_APPEND,    O_APPEND,    O_APPEND,    },
+       { TARGET_O_NONBLOCK,  TARGET_O_NONBLOCK,  O_NONBLOCK,  O_NONBLOCK,  },
+       { TARGET_O_SYNC,      TARGET_O_SYNC,      O_SYNC,      O_SYNC,      },
+       { TARGET_FASYNC,      TARGET_FASYNC,      FASYNC,      FASYNC,      },
+       { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
+       { TARGET_O_NOFOLLOW,  TARGET_O_NOFOLLOW,  O_NOFOLLOW,  O_NOFOLLOW,  },
+       { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
+       { TARGET_O_DIRECT,    TARGET_O_DIRECT,    O_DIRECT,    O_DIRECT,    },
+       { 0, 0, 0, 0 }
+};
+
 #if defined(TARGET_I386)
 
 /* NOTE: there is really one LDT for all the threads */
@@ -1264,7 +1308,16 @@ 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)
-               printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
+        printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
+#elif defined(TARGET_PPC)
+        if (!newsp)
+            newsp = env->gpr[1];
+        new_env->gpr[1] = newsp;
+        { 
+            int i;
+            for (i = 7; i < 32; i++)
+                new_env->gpr[i] = 0;
+        }
 #else
 #error unsupported target CPU
 #endif
@@ -1318,6 +1371,15 @@ static long do_fcntl(int fd, int cmd, unsigned long arg)
         errno = EINVAL;
         break;
 
+    case F_GETFL:
+        ret = fcntl(fd, cmd, arg);
+        ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
+        break;
+
+    case F_SETFL:
+        ret = fcntl(fd, cmd, target_to_host_bitmask(arg, fcntl_flags_tbl));
+        break;
+
     default:
         ret = fcntl(fd, cmd, arg);
         break;
@@ -1325,11 +1387,41 @@ static long do_fcntl(int fd, int cmd, unsigned long arg)
     return ret;
 }
 
+#ifdef USE_UID16
+
+static inline int high2lowuid(int uid)
+{
+    if (uid > 65535)
+        return 65534;
+    else
+        return uid;
+}
+
+static inline int high2lowgid(int gid)
+{
+    if (gid > 65535)
+        return 65534;
+    else
+        return gid;
+}
+
+static inline int low2highuid(int uid)
+{
+    if ((int16_t)uid == -1)
+        return -1;
+    else
+        return uid;
+}
+
+static inline int low2highgid(int gid)
+{
+    if ((int16_t)gid == -1)
+        return -1;
+    else
+        return gid;
+}
 
-#define high2lowuid(x) (x)
-#define high2lowgid(x) (x)
-#define low2highuid(x) (x)
-#define low2highgid(x) (x)
+#endif /* USE_UID16 */
 
 void syscall_init(void)
 {
@@ -1371,7 +1463,7 @@ void syscall_init(void)
         ie++;
     }
 }
-                                 
+
 long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, 
                 long arg4, long arg5, long arg6)
 {
@@ -1380,7 +1472,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
     struct kernel_statfs *stfs;
     
 #ifdef DEBUG
-    gemu_log("syscall %d\n", num);
+    gemu_log("syscall %d", num);
 #endif
     switch(num) {
     case TARGET_NR_exit:
@@ -1399,7 +1491,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
         ret = get_errno(write(arg1, (void *)arg2, arg3));
         break;
     case TARGET_NR_open:
-        ret = get_errno(open(path((const char *)arg1), arg2, arg3));
+        ret = get_errno(open(path((const char *)arg1),
+                             target_to_host_bitmask(arg2, fcntl_flags_tbl),
+                             arg3));
         break;
     case TARGET_NR_close:
         ret = get_errno(close(arg1));
@@ -1472,9 +1566,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
     case TARGET_NR_chmod:
         ret = get_errno(chmod((const char *)arg1, arg2));
         break;
-    case TARGET_NR_lchown:
-        ret = get_errno(chown((const char *)arg1, arg2, arg3));
-        break;
 #ifdef TARGET_NR_break
     case TARGET_NR_break:
         goto unimplemented;
@@ -1495,12 +1586,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
     case TARGET_NR_umount:
         ret = get_errno(umount((const char *)arg1));
         break;
-    case TARGET_NR_setuid:
-        ret = get_errno(setuid(low2highuid(arg1)));
-        break;
-    case TARGET_NR_getuid:
-        ret = get_errno(getuid());
-        break;
     case TARGET_NR_stime:
         {
             int *time_ptr = (int *)arg1;
@@ -1596,20 +1681,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
     case TARGET_NR_prof:
         goto unimplemented;
 #endif
-    case TARGET_NR_setgid:
-        ret = get_errno(setgid(low2highgid(arg1)));
-        break;
-    case TARGET_NR_getgid:
-        ret = get_errno(getgid());
-        break;
     case TARGET_NR_signal:
         goto unimplemented;
-    case TARGET_NR_geteuid:
-        ret = get_errno(geteuid());
-        break;
-    case TARGET_NR_getegid:
-        ret = get_errno(getegid());
-        break;
+
     case TARGET_NR_acct:
         goto unimplemented;
     case TARGET_NR_umount2:
@@ -1844,12 +1918,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
         /* NOTE: ret is eax, so not transcoding must be done */
         ret = do_rt_sigreturn(cpu_env);
         break;
-    case TARGET_NR_setreuid:
-        ret = get_errno(setreuid(arg1, arg2));
-        break;
-    case TARGET_NR_setregid:
-        ret = get_errno(setregid(arg1, arg2));
-        break;
     case TARGET_NR_sethostname:
         ret = get_errno(sethostname((const char *)arg1, arg2));
         break;
@@ -1906,34 +1974,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
             ret = get_errno(settimeofday(&tv, NULL));
         }
         break;
-    case TARGET_NR_getgroups:
-        {
-            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:
-        {
-            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:
         {
             struct target_sel_arg_struct *sel = (void *)arg1;
@@ -1988,10 +2028,15 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
 #endif
         break;
     case TARGET_NR_mmap2:
+#if defined(TARGET_SPARC)
+#define MMAP_SHIFT 12
+#else
+#define MMAP_SHIFT TARGET_PAGE_BITS
+#endif
         ret = get_errno(target_mmap(arg1, arg2, arg3, 
                                     target_to_host_bitmask(arg4, mmap_flags_tbl), 
                                     arg5,
-                                    arg6 << TARGET_PAGE_BITS));
+                                    arg6 << MMAP_SHIFT));
         break;
     case TARGET_NR_munmap:
         ret = get_errno(target_munmap(arg1, arg2));
@@ -2026,9 +2071,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
     case TARGET_NR_fchmod:
         ret = get_errno(fchmod(arg1, arg2));
         break;
-    case TARGET_NR_fchown:
-        ret = get_errno(fchown(arg1, arg2, arg3));
-        break;
     case TARGET_NR_getpriority:
         ret = get_errno(getpriority(arg1, arg2));
         break;
@@ -2121,10 +2163,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
                 struct target_stat *target_st = (void *)arg2;
                 target_st->st_dev = tswap16(st.st_dev);
                 target_st->st_ino = tswapl(st.st_ino);
+#if defined(TARGET_PPC)
+                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);
+#else
                 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);
+#endif
+                target_st->st_nlink = tswap16(st.st_nlink);
                 target_st->st_rdev = tswap16(st.st_rdev);
                 target_st->st_size = tswapl(st.st_size);
                 target_st->st_blksize = tswapl(st.st_blksize);
@@ -2230,12 +2278,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
         break;
     case TARGET_NR_afs_syscall:
         goto unimplemented;
-    case TARGET_NR_setfsuid:
-        ret = get_errno(setfsuid(arg1));
-        break;
-    case TARGET_NR_setfsgid:
-        ret = get_errno(setfsgid(arg1));
-        break;
     case TARGET_NR__llseek:
         {
             int64_t res;
@@ -2465,52 +2507,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
             }
         }
         break;
-#ifdef TARGET_NR_setresuid
-    case TARGET_NR_setresuid:
-        ret = get_errno(setresuid(low2highuid(arg1), 
-                                  low2highuid(arg2), 
-                                  low2highuid(arg3)));
-        break;
-#endif
-#ifdef TARGET_NR_getresuid
-    case TARGET_NR_getresuid:
-        {
-            int ruid, euid, suid;
-            ret = get_errno(getresuid(&ruid, &euid, &suid));
-            if (!is_error(ret)) {
-                *(uint16_t *)arg1 = tswap16(high2lowuid(ruid));
-                *(uint16_t *)arg2 = tswap16(high2lowuid(euid));
-                *(uint16_t *)arg3 = tswap16(high2lowuid(suid));
-            }
-        }
-        break;
-#endif
-#ifdef TARGET_NR_getresgid
-    case TARGET_NR_setresgid:
-        ret = get_errno(setresgid(low2highgid(arg1), 
-                                  low2highgid(arg2), 
-                                  low2highgid(arg3)));
-        break;
-#endif
-#ifdef TARGET_NR_getresgid
-    case TARGET_NR_getresgid:
-        {
-            int rgid, egid, sgid;
-            ret = get_errno(getresgid(&rgid, &egid, &sgid));
-            if (!is_error(ret)) {
-                *(uint16_t *)arg1 = high2lowgid(tswap16(rgid));
-                *(uint16_t *)arg2 = high2lowgid(tswap16(egid));
-                *(uint16_t *)arg3 = high2lowgid(tswap16(sgid));
-            }
-        }
-        break;
-#endif
     case TARGET_NR_query_module:
         goto unimplemented;
     case TARGET_NR_nfsservctl:
         goto unimplemented;
     case TARGET_NR_prctl:
         goto unimplemented;
+#ifdef TARGET_NR_pread
     case TARGET_NR_pread:
         page_unprotect_range((void *)arg2, arg3);
         ret = get_errno(pread(arg1, (void *)arg2, arg3, arg4));
@@ -2518,9 +2521,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
     case TARGET_NR_pwrite:
         ret = get_errno(pwrite(arg1, (void *)arg2, arg3, arg4));
         break;
-    case TARGET_NR_chown:
-        ret = get_errno(chown((const char *)arg1, arg2, arg3));
-        break;
+#endif
     case TARGET_NR_getcwd:
         ret = get_errno(sys_getcwd1((char *)arg1, arg2));
         break;
@@ -2573,26 +2574,136 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
             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 = tswap64(st.st_ino);
+                put_user(st.st_dev, &target_st->st_dev);
+                put_user(st.st_ino, &target_st->st_ino);
 #ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
-                target_st->__st_ino = tswapl(st.st_ino);
+                put_user(st.st_ino, &target_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);
+                put_user(st.st_mode, &target_st->st_mode);
+                put_user(st.st_nlink, &target_st->st_nlink);
+                put_user(st.st_uid, &target_st->st_uid);
+                put_user(st.st_gid, &target_st->st_gid);
+                put_user(st.st_rdev, &target_st->st_rdev);
                 /* XXX: better use of kernel struct */
-                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->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);
+                put_user(st.st_size, &target_st->st_size);
+                put_user(st.st_blksize, &target_st->st_blksize);
+                put_user(st.st_blocks, &target_st->st_blocks);
+                put_user(st.st_atime, &target_st->target_st_atime);
+                put_user(st.st_mtime, &target_st->target_st_mtime);
+                put_user(st.st_ctime, &target_st->target_st_ctime);
+            }
+        }
+        break;
+
+#ifdef USE_UID16
+    case TARGET_NR_lchown:
+        ret = get_errno(lchown((const char *)arg1, low2highuid(arg2), low2highgid(arg3)));
+        break;
+    case TARGET_NR_getuid:
+        ret = get_errno(high2lowuid(getuid()));
+        break;
+    case TARGET_NR_getgid:
+        ret = get_errno(high2lowgid(getgid()));
+        break;
+    case TARGET_NR_geteuid:
+        ret = get_errno(high2lowuid(geteuid()));
+        break;
+    case TARGET_NR_getegid:
+        ret = get_errno(high2lowgid(getegid()));
+        break;
+    case TARGET_NR_setreuid:
+        ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
+        break;
+    case TARGET_NR_setregid:
+        ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
+        break;
+    case TARGET_NR_getgroups:
+        {
+            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:
+        {
+            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_fchown:
+        ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
+        break;
+#ifdef TARGET_NR_setresuid
+    case TARGET_NR_setresuid:
+        ret = get_errno(setresuid(low2highuid(arg1), 
+                                  low2highuid(arg2), 
+                                  low2highuid(arg3)));
+        break;
+#endif
+#ifdef TARGET_NR_getresuid
+    case TARGET_NR_getresuid:
+        {
+            int ruid, euid, suid;
+            ret = get_errno(getresuid(&ruid, &euid, &suid));
+            if (!is_error(ret)) {
+                *(uint16_t *)arg1 = tswap16(high2lowuid(ruid));
+                *(uint16_t *)arg2 = tswap16(high2lowuid(euid));
+                *(uint16_t *)arg3 = tswap16(high2lowuid(suid));
             }
         }
         break;
+#endif
+#ifdef TARGET_NR_getresgid
+    case TARGET_NR_setresgid:
+        ret = get_errno(setresgid(low2highgid(arg1), 
+                                  low2highgid(arg2), 
+                                  low2highgid(arg3)));
+        break;
+#endif
+#ifdef TARGET_NR_getresgid
+    case TARGET_NR_getresgid:
+        {
+            int rgid, egid, sgid;
+            ret = get_errno(getresgid(&rgid, &egid, &sgid));
+            if (!is_error(ret)) {
+                *(uint16_t *)arg1 = tswap16(high2lowgid(rgid));
+                *(uint16_t *)arg2 = tswap16(high2lowgid(egid));
+                *(uint16_t *)arg3 = tswap16(high2lowgid(sgid));
+            }
+        }
+        break;
+#endif
+    case TARGET_NR_chown:
+        ret = get_errno(chown((const char *)arg1, low2highuid(arg2), low2highgid(arg3)));
+        break;
+    case TARGET_NR_setuid:
+        ret = get_errno(setuid(low2highuid(arg1)));
+        break;
+    case TARGET_NR_setgid:
+        ret = get_errno(setgid(low2highgid(arg1)));
+        break;
+    case TARGET_NR_setfsuid:
+        ret = get_errno(setfsuid(arg1));
+        break;
+    case TARGET_NR_setfsgid:
+        ret = get_errno(setfsgid(arg1));
+        break;
+#endif /* USE_UID16 */
 
     case TARGET_NR_lchown32:
         ret = get_errno(lchown((const char *)arg1, arg2, arg3));
@@ -2665,12 +2776,17 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
     case TARGET_NR_setfsgid32:
         ret = get_errno(setfsgid(arg1));
         break;
+
     case TARGET_NR_pivot_root:
         goto unimplemented;
+#ifdef TARGET_NR_mincore
     case TARGET_NR_mincore:
         goto unimplemented;
+#endif
+#ifdef TARGET_NR_madvise
     case TARGET_NR_madvise:
         goto unimplemented;
+#endif
 #if TARGET_LONG_BITS == 32
     case TARGET_NR_fcntl64:
     {
@@ -2709,6 +2825,11 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
     case TARGET_NR_security:
         goto unimplemented;
 #endif
+#ifdef TARGET_NR_getpagesize
+    case TARGET_NR_getpagesize:
+        ret = TARGET_PAGE_SIZE;
+        break;
+#endif
     case TARGET_NR_gettid:
         ret = get_errno(gettid());
         break;
@@ -2742,6 +2863,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
         break;
     }
  fail:
+#ifdef DEBUG
+    gemu_log(" = %ld\n", ret);
+#endif
     return ret;
 }