fixed invalid Linux asm/unistd.h header for PowerPC and gcc 3.3
[qemu] / linux-user / syscall.c
index 9b02d5e..753a47c 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);
+
+#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
+
+/* 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 __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)                                                  \
+{                                                                      \
+       __syscall_nr(1, type, name, arg1);                              \
+}
+
+#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)                          \
+{                                                                      \
+       __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)              \
+{                                                                      \
+       __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)  \
+{                                                                      \
+       __syscall_nr(5, type, name, arg1, arg2, arg3, arg4, arg5);      \
+}
+#endif
 
 #define __NR_sys_uname __NR_uname
 #define __NR_sys_getcwd1 __NR_getcwd
@@ -215,6 +333,21 @@ static inline void host_to_target_fds(target_long *target_fds,
 #endif
 }
 
+#if defined(__alpha__)
+#define HOST_HZ 1024
+#else
+#define HOST_HZ 100
+#endif
+
+static inline long host_to_target_clock_t(long ticks)
+{
+#if HOST_HZ == TARGET_HZ
+    return ticks;
+#else
+    return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
+#endif
+}
+
 static inline void host_to_target_rusage(struct target_rusage *target_rusage, 
                                          const struct rusage *rusage)
 {
@@ -702,8 +835,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];
@@ -715,7 +848,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"
@@ -970,7 +1103,7 @@ static bitmask_transtbl mmap_flags_tbl[] = {
        { 0, 0, 0, 0 }
 };
 
-#ifdef TARGET_I386
+#if defined(TARGET_I386)
 
 /* NOTE: there is really one LDT for all the threads */
 uint8_t *ldt_table;
@@ -1087,28 +1220,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;
@@ -1117,10 +1250,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);
@@ -1136,8 +1280,6 @@ 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;
@@ -1188,11 +1330,43 @@ static long do_fcntl(int fd, int cmd, unsigned long arg)
 
 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, 
@@ -1387,11 +1561,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
             struct tms tms;
             ret = get_errno(times(&tms));
             if (tmsp) {
-                tmsp->tms_utime = tswapl(tms.tms_utime);
-                tmsp->tms_stime = tswapl(tms.tms_stime);
-                tmsp->tms_cutime = tswapl(tms.tms_cutime);
-                tmsp->tms_cstime = tswapl(tms.tms_cstime);
+                tmsp->tms_utime = tswapl(host_to_target_clock_t(tms.tms_utime));
+                tmsp->tms_stime = tswapl(host_to_target_clock_t(tms.tms_stime));
+                tmsp->tms_cutime = tswapl(host_to_target_clock_t(tms.tms_cutime));
+                tmsp->tms_cstime = tswapl(host_to_target_clock_t(tms.tms_cstime));
             }
+            if (!is_error(ret))
+                ret = host_to_target_clock_t(ret);
         }
         break;
     case TARGET_NR_prof:
@@ -1727,7 +1903,17 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
         }
         break;
     case TARGET_NR_select:
-        goto unimplemented;
+        {
+            struct target_sel_arg_struct *sel = (void *)arg1;
+            sel->n = tswapl(sel->n);
+            sel->inp = tswapl(sel->inp);
+            sel->outp = tswapl(sel->outp);
+            sel->exp = tswapl(sel->exp);
+            sel->tvp = tswapl(sel->tvp);
+            ret = do_select(sel->n, (void *)sel->inp, (void *)sel->outp,
+                            (void *)sel->exp, (void *)sel->tvp);
+        }
+        break;
     case TARGET_NR_symlink:
         ret = get_errno(symlink((const char *)arg1, (const char *)arg2));
         break;
@@ -1745,8 +1931,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
         goto unimplemented;
     case TARGET_NR_readdir:
         goto unimplemented;
-#ifdef TARGET_I386
     case TARGET_NR_mmap:
+#if defined(TARGET_I386) || defined(TARGET_ARM)
         {
             uint32_t v1, v2, v3, v4, v5, v6, *vptr;
             vptr = (uint32_t *)arg1;
@@ -1760,13 +1946,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
                                         target_to_host_bitmask(v4, mmap_flags_tbl),
                                         v5, v6));
         }
-        break;
-#endif
-#ifdef TARGET_I386
-    case TARGET_NR_mmap2:
 #else
-    case TARGET_NR_mmap:
+        ret = get_errno(target_mmap(arg1, arg2, arg3, 
+                                    target_to_host_bitmask(arg4, mmap_flags_tbl), 
+                                    arg5,
+                                    arg6));
 #endif
+        break;
+    case TARGET_NR_mmap2:
         ret = get_errno(target_mmap(arg1, arg2, arg3, 
                                     target_to_host_bitmask(arg4, mmap_flags_tbl), 
                                     arg5,