]> git.proxmox.com Git - qemu.git/commitdiff
first vm86 support
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 29 Mar 2003 16:54:36 +0000 (16:54 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 29 Mar 2003 16:54:36 +0000 (16:54 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@60 c046a42c-6fe2-441c-8c8c-71466251a162

linux-user/syscall.c

index f0f790f5f863993ab6c0ba61d0fe1e7c250874f4..2d8804e12a36c5d603d91323cd13dbb8ed5055ee 100644 (file)
@@ -103,10 +103,10 @@ extern int personality(int);
 extern int flock(int, int);
 extern int setfsuid(int);
 extern int setfsgid(int);
-extern int setresuid(int,int,int);
-extern int getresuid(int *,int *,int *);
-extern int setresgid(int,int,int);
-extern int getresgid(int *,int *,int *);
+extern int setresuid(uid_t, uid_t, uid_t);
+extern int getresuid(uid_t *, uid_t *, uid_t *);
+extern int setresgid(gid_t, gid_t, gid_t);
+extern int getresgid(gid_t *, gid_t *, gid_t *);
 
 static inline long get_errno(long ret)
 {
@@ -210,14 +210,14 @@ static inline void host_to_target_fds(target_long *target_fds,
 }
 
 static inline void target_to_host_timeval(struct timeval *tv, 
-                                          struct target_timeval *target_tv)
+                                          const struct target_timeval *target_tv)
 {
     tv->tv_sec = tswapl(target_tv->tv_sec);
     tv->tv_usec = tswapl(target_tv->tv_usec);
 }
 
 static inline void host_to_target_timeval(struct target_timeval *target_tv, 
-                                          struct timeval *tv)
+                                          const struct timeval *tv)
 {
     target_tv->tv_sec = tswapl(tv->tv_sec);
     target_tv->tv_usec = tswapl(tv->tv_usec);
@@ -238,8 +238,7 @@ static long do_select(long n,
     efds_ptr = target_to_host_fds(&efds, target_efds, n);
             
     if (target_tv) {
-        tv.tv_sec = tswapl(target_tv->tv_sec);
-        tv.tv_usec = tswapl(target_tv->tv_usec);
+        target_to_host_timeval(&tv, target_tv);
         tv_ptr = &tv;
     } else {
         tv_ptr = NULL;
@@ -251,8 +250,7 @@ static long do_select(long n,
         host_to_target_fds(target_efds, efds_ptr, n);
 
         if (target_tv) {
-            target_tv->tv_sec = tswapl(tv.tv_sec);
-            target_tv->tv_usec = tswapl(tv.tv_usec);
+            host_to_target_timeval(target_tv, &tv);
         }
     }
     return ret;
@@ -755,7 +753,7 @@ install:
 }
 
 /* specific and weird i386 syscalls */
-int gemu_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecount)
+int do_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecount)
 {
     int ret = -ENOSYS;
     
@@ -773,6 +771,79 @@ int gemu_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecou
     return ret;
 }
 
+/* vm86 emulation */
+
+#define SAFE_MASK  (0xDD5)
+
+int do_vm86(CPUX86State *env, long subfunction, 
+            struct target_vm86plus_struct * target_v86)
+{
+    TaskState *ts = env->opaque;
+    int ret;
+    
+    switch (subfunction) {
+    case TARGET_VM86_REQUEST_IRQ:
+    case TARGET_VM86_FREE_IRQ:
+    case TARGET_VM86_GET_IRQ_BITS:
+    case TARGET_VM86_GET_AND_RESET_IRQ:
+        gemu_log("qemu: unsupported vm86 subfunction (%ld)\n", subfunction);
+        ret = -EINVAL;
+        goto out;
+    case TARGET_VM86_PLUS_INSTALL_CHECK:
+        /* NOTE: on old vm86 stuff this will return the error
+           from verify_area(), because the subfunction is
+           interpreted as (invalid) address to vm86_struct.
+           So the installation check works.
+            */
+        ret = 0;
+        goto out;
+    }
+
+    ts->target_v86 = target_v86;
+
+    /* save current CPU regs */
+    ts->vm86_saved_regs.eax = 0; /* default vm86 syscall return code */
+    ts->vm86_saved_regs.ebx = env->regs[R_EBX];
+    ts->vm86_saved_regs.ecx = env->regs[R_ECX];
+    ts->vm86_saved_regs.edx = env->regs[R_EDX];
+    ts->vm86_saved_regs.esi = env->regs[R_ESI];
+    ts->vm86_saved_regs.edi = env->regs[R_EDI];
+    ts->vm86_saved_regs.ebp = env->regs[R_EBP];
+    ts->vm86_saved_regs.esp = env->regs[R_ESP];
+    ts->vm86_saved_regs.eflags = env->eflags;
+    ts->vm86_saved_regs.eip  = env->eip;
+    ts->vm86_saved_regs.cs = env->segs[R_CS];
+    ts->vm86_saved_regs.ss = env->segs[R_SS];
+    ts->vm86_saved_regs.ds = env->segs[R_DS];
+    ts->vm86_saved_regs.es = env->segs[R_ES];
+    ts->vm86_saved_regs.fs = env->segs[R_FS];
+    ts->vm86_saved_regs.gs = env->segs[R_GS];
+
+    /* build vm86 CPU state */
+    env->eflags = (env->eflags & ~SAFE_MASK) | 
+        (tswap32(target_v86->regs.eflags) & SAFE_MASK) | VM_MASK;
+
+    env->regs[R_EBX] = tswap32(target_v86->regs.ebx);
+    env->regs[R_ECX] = tswap32(target_v86->regs.ecx);
+    env->regs[R_EDX] = tswap32(target_v86->regs.edx);
+    env->regs[R_ESI] = tswap32(target_v86->regs.esi);
+    env->regs[R_EDI] = tswap32(target_v86->regs.edi);
+    env->regs[R_EBP] = tswap32(target_v86->regs.ebp);
+    env->regs[R_ESP] = tswap32(target_v86->regs.esp);
+    env->eip = tswap32(target_v86->regs.eip);
+    cpu_x86_load_seg(env, R_CS, tswap16(target_v86->regs.cs));
+    cpu_x86_load_seg(env, R_SS, tswap16(target_v86->regs.ss));
+    cpu_x86_load_seg(env, R_DS, tswap16(target_v86->regs.ds));
+    cpu_x86_load_seg(env, R_ES, tswap16(target_v86->regs.es));
+    cpu_x86_load_seg(env, R_FS, tswap16(target_v86->regs.fs));
+    cpu_x86_load_seg(env, R_GS, tswap16(target_v86->regs.gs));
+    ret = tswap32(target_v86->regs.eax); /* eax will be restored at
+                                            the end of the syscall */
+    /* now the virtual CPU is ready for vm86 execution ! */
+ out:
+    return ret;
+}
+
 /* this stack is the equivalent of the kernel stack associated with a
    thread/process */
 #define NEW_STACK_SIZE 8192
@@ -788,19 +859,26 @@ static int clone_func(void *arg)
 int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp)
 {
     int ret;
+    TaskState *ts;
     uint8_t *new_stack;
     CPUX86State *new_env;
     
     if (flags & CLONE_VM) {
         if (!newsp)
             newsp = env->regs[R_ESP];
-        new_stack = malloc(NEW_STACK_SIZE);
-        
+        ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE);
+        memset(ts, 0, sizeof(TaskState));
+        new_stack = ts->stack;
+        ts->used = 1;
+        /* add in task state list */
+        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->regs[R_ESP] = newsp;
         new_env->regs[R_EAX] = 0;
+        new_env->opaque = ts;
         ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
     } else {
         /* if no CLONE_VM, we consider it is a fork */
@@ -1281,8 +1359,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
             struct timeval tv;
             ret = get_errno(gettimeofday(&tv, NULL));
             if (!is_error(ret)) {
-                target_tv->tv_sec = tswapl(tv.tv_sec);
-                target_tv->tv_usec = tswapl(tv.tv_usec);
+                host_to_target_timeval(target_tv, &tv);
             }
         }
         break;
@@ -1290,8 +1367,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
         {
             struct target_timeval *target_tv = (void *)arg1;
             struct timeval tv;
-            tv.tv_sec = tswapl(target_tv->tv_sec);
-            tv.tv_usec = tswapl(target_tv->tv_usec);
+            target_to_host_timeval(&tv, target_tv);
             ret = get_errno(settimeofday(&tv, NULL));
         }
         break;
@@ -1487,8 +1563,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
         break;
     case TARGET_NR_idle:
         goto unimplemented;
-    case TARGET_NR_vm86old:
-        goto unimplemented;
     case TARGET_NR_wait4:
         {
             int status;
@@ -1548,7 +1622,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
         break;
 #ifdef TARGET_I386
     case TARGET_NR_modify_ldt:
-        ret = get_errno(gemu_modify_ldt(cpu_env, arg1, (void *)arg2, arg3));
+        ret = get_errno(do_modify_ldt(cpu_env, arg1, (void *)arg2, arg3));
+        break;
+    case TARGET_NR_vm86old:
+        goto unimplemented;
+    case TARGET_NR_vm86:
+        ret = do_vm86(cpu_env, arg1, (void *)arg2);
         break;
 #endif
     case TARGET_NR_adjtimex:
@@ -1652,13 +1731,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
 
             pfd = alloca(sizeof(struct pollfd) * nfds);
             for(i = 0; i < nfds; i++) {
-                pfd->fd = tswap32(target_pfd->fd);
-                pfd->events = tswap16(target_pfd->events);
+                pfd[i].fd = tswap32(target_pfd[i].fd);
+                pfd[i].events = tswap16(target_pfd[i].events);
             }
             ret = get_errno(poll(pfd, nfds, timeout));
             if (!is_error(ret)) {
                 for(i = 0; i < nfds; i++) {
-                    target_pfd->revents = tswap16(pfd->revents);
+                    target_pfd[i].revents = tswap16(pfd[i].revents);
                 }
             }
         }
@@ -1702,25 +1781,59 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
         ret = get_errno(getsid(arg1));
         break;
     case TARGET_NR_fdatasync:
-        goto unimplemented;
+        ret = get_errno(fdatasync(arg1));
+        break;
     case TARGET_NR__sysctl:
         goto unimplemented;
     case TARGET_NR_sched_setparam:
-        goto unimplemented;
+        {
+            struct sched_param *target_schp = (void *)arg2;
+            struct sched_param schp;
+            schp.sched_priority = tswap32(target_schp->sched_priority);
+            ret = get_errno(sched_setparam(arg1, &schp));
+        }
+        break;
     case TARGET_NR_sched_getparam:
-        goto unimplemented;
+        {
+            struct sched_param *target_schp = (void *)arg2;
+            struct sched_param schp;
+            ret = get_errno(sched_getparam(arg1, &schp));
+            if (!is_error(ret)) {
+                target_schp->sched_priority = tswap32(schp.sched_priority);
+            }
+        }
+        break;
     case TARGET_NR_sched_setscheduler:
-        goto unimplemented;
+        {
+            struct sched_param *target_schp = (void *)arg3;
+            struct sched_param schp;
+            schp.sched_priority = tswap32(target_schp->sched_priority);
+            ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
+        }
+        break;
     case TARGET_NR_sched_getscheduler:
-        goto unimplemented;
+        ret = get_errno(sched_getscheduler(arg1));
+        break;
     case TARGET_NR_sched_yield:
         ret = get_errno(sched_yield());
         break;
     case TARGET_NR_sched_get_priority_max:
+        ret = get_errno(sched_get_priority_max(arg1));
+        break;
     case TARGET_NR_sched_get_priority_min:
+        ret = get_errno(sched_get_priority_min(arg1));
+        break;
     case TARGET_NR_sched_rr_get_interval:
-        goto unimplemented;
-        
+        {
+            struct target_timespec *target_ts = (void *)arg2;
+            struct timespec ts;
+            ret = get_errno(sched_rr_get_interval(arg1, &ts));
+            if (!is_error(ret)) {
+                target_ts->tv_sec = tswapl(ts.tv_sec);
+                target_ts->tv_nsec = tswapl(ts.tv_nsec);
+            }
+        }
+        break;
     case TARGET_NR_nanosleep:
         {
             struct target_timespec *target_req = (void *)arg1;
@@ -1767,11 +1880,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
             }
         }
         break;
-    case TARGET_NR_vm86:
     case TARGET_NR_query_module:
+        goto unimplemented;
     case TARGET_NR_nfsservctl:
+        goto unimplemented;
     case TARGET_NR_prctl:
+        goto unimplemented;
     case TARGET_NR_pread:
+        goto unimplemented;
     case TARGET_NR_pwrite:
         goto unimplemented;
     case TARGET_NR_chown:
@@ -1781,16 +1897,24 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
         ret = get_errno(sys_getcwd1((char *)arg1, arg2));
         break;
     case TARGET_NR_capget:
+        goto unimplemented;
     case TARGET_NR_capset:
+        goto unimplemented;
     case TARGET_NR_sigaltstack:
+        goto unimplemented;
     case TARGET_NR_sendfile:
+        goto unimplemented;
     case TARGET_NR_getpmsg:
+        goto unimplemented;
     case TARGET_NR_putpmsg:
+        goto unimplemented;
     case TARGET_NR_vfork:
         ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0));
         break;
     case TARGET_NR_ugetrlimit:
+        goto unimplemented;
     case TARGET_NR_truncate64:
+        goto unimplemented;
     case TARGET_NR_ftruncate64:
         goto unimplemented;
     case TARGET_NR_stat64:
@@ -1919,6 +2043,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
         ret = get_errno(gettid());
         break;
     case TARGET_NR_readahead:
+        goto unimplemented;
     case TARGET_NR_setxattr:
     case TARGET_NR_lsetxattr:
     case TARGET_NR_fsetxattr:
@@ -1931,10 +2056,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
     case TARGET_NR_removexattr:
     case TARGET_NR_lremovexattr:
     case TARGET_NR_fremovexattr:
-        goto unimplemented;
+        goto unimplemented_nowarn;
+    case TARGET_NR_set_thread_area:
+    case TARGET_NR_get_thread_area:
+        goto unimplemented_nowarn;
     default:
     unimplemented:
-        gemu_log("gemu: Unsupported syscall: %d\n", num);
+        gemu_log("qemu: Unsupported syscall: %d\n", num);
+    unimplemented_nowarn:
         ret = -ENOSYS;
         break;
     }