summary refs log tree commit diff stats
path: root/bsd-user/main.c
diff options
context:
space:
mode:
authorJuergen Lock <nox@jelal.kn-bremen.de>2009-10-17 00:34:26 +0200
committerBlue Swirl <blauwirbel@gmail.com>2009-10-18 15:16:08 +0000
commit78cfb07fe0dc556cae662a0fab5fe1bd33daabdb (patch)
tree9d8123e0e1875cfbd1ba7544122f31b4519e7e80 /bsd-user/main.c
parent976b2037e5eaa7dc18ca7062c9276ec03aaa37a9 (diff)
downloadfocaccia-qemu-78cfb07fe0dc556cae662a0fab5fe1bd33daabdb.tar.gz
focaccia-qemu-78cfb07fe0dc556cae662a0fab5fe1bd33daabdb.zip
bsd-user: FreeBSD update
basic FreeBSD sysarch(2) handling
fixed syscall errno return

Signed-off-by: Juergen Lock <nox@jelal.kn-bremen.de>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Diffstat (limited to 'bsd-user/main.c')
-rw-r--r--bsd-user/main.c116
1 files changed, 94 insertions, 22 deletions
diff --git a/bsd-user/main.c b/bsd-user/main.c
index 1bba2b5055..19b7f3a1f7 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -46,6 +46,7 @@ int have_guest_base;
 static const char *interp_prefix = CONFIG_QEMU_PREFIX;
 const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
 extern char **environ;
+enum BSDType bsd_type;
 
 /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
    we allocate a bigger stack. Need a better solution, for example
@@ -168,7 +169,7 @@ static void set_idt(int n, unsigned int dpl)
 }
 #endif
 
-void cpu_loop(CPUX86State *env, enum BSDType bsd_type)
+void cpu_loop(CPUX86State *env)
 {
     int trapnr;
     abi_ulong pc;
@@ -179,27 +180,90 @@ void cpu_loop(CPUX86State *env, enum BSDType bsd_type)
         switch(trapnr) {
         case 0x80:
             /* syscall from int $0x80 */
-            env->regs[R_EAX] = do_openbsd_syscall(env,
-                                                  env->regs[R_EAX],
-                                                  env->regs[R_EBX],
-                                                  env->regs[R_ECX],
-                                                  env->regs[R_EDX],
-                                                  env->regs[R_ESI],
-                                                  env->regs[R_EDI],
-                                                  env->regs[R_EBP]);
+            if (bsd_type == target_freebsd) {
+                abi_ulong params = (abi_ulong) env->regs[R_ESP] +
+                    sizeof(int32_t);
+                int32_t syscall_nr = env->regs[R_EAX];
+                int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
+
+                if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
+                    get_user_s32(syscall_nr, params);
+                    params += sizeof(int32_t);
+                } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) {
+                    get_user_s32(syscall_nr, params);
+                    params += sizeof(int64_t);
+                }
+                get_user_s32(arg1, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg2, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg3, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg4, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg5, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg6, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg7, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg8, params);
+                env->regs[R_EAX] = do_freebsd_syscall(env,
+                                                      syscall_nr,
+                                                      arg1,
+                                                      arg2,
+                                                      arg3,
+                                                      arg4,
+                                                      arg5,
+                                                      arg6,
+                                                      arg7,
+                                                      arg8);
+            } else { //if (bsd_type == target_openbsd)
+                env->regs[R_EAX] = do_openbsd_syscall(env,
+                                                      env->regs[R_EAX],
+                                                      env->regs[R_EBX],
+                                                      env->regs[R_ECX],
+                                                      env->regs[R_EDX],
+                                                      env->regs[R_ESI],
+                                                      env->regs[R_EDI],
+                                                      env->regs[R_EBP]);
+            }
+            if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
+                env->regs[R_EAX] = -env->regs[R_EAX];
+                env->eflags |= CC_C;
+            } else {
+                env->eflags &= ~CC_C;
+            }
             break;
 #ifndef TARGET_ABI32
         case EXCP_SYSCALL:
-            /* linux syscall from syscall intruction */
-            env->regs[R_EAX] = do_openbsd_syscall(env,
-                                                  env->regs[R_EAX],
-                                                  env->regs[R_EDI],
-                                                  env->regs[R_ESI],
-                                                  env->regs[R_EDX],
-                                                  env->regs[10],
-                                                  env->regs[8],
-                                                  env->regs[9]);
+            /* syscall from syscall intruction */
+            if (bsd_type == target_freebsd)
+                env->regs[R_EAX] = do_freebsd_syscall(env,
+                                                      env->regs[R_EAX],
+                                                      env->regs[R_EDI],
+                                                      env->regs[R_ESI],
+                                                      env->regs[R_EDX],
+                                                      env->regs[R_ECX],
+                                                      env->regs[8],
+                                                      env->regs[9], 0, 0);
+            else { //if (bsd_type == target_openbsd)
+                env->regs[R_EAX] = do_openbsd_syscall(env,
+                                                      env->regs[R_EAX],
+                                                      env->regs[R_EDI],
+                                                      env->regs[R_ESI],
+                                                      env->regs[R_EDX],
+                                                      env->regs[10],
+                                                      env->regs[8],
+                                                      env->regs[9]);
+            }
             env->eip = env->exception_next_eip;
+            if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
+                env->regs[R_EAX] = -env->regs[R_EAX];
+                env->eflags |= CC_C;
+            } else {
+                env->eflags &= ~CC_C;
+            }
             break;
 #endif
 #if 0
@@ -446,7 +510,7 @@ static void flush_windows(CPUSPARCState *env)
 #endif
 }
 
-void cpu_loop(CPUSPARCState *env, enum BSDType bsd_type)
+void cpu_loop(CPUSPARCState *env)
 {
     int trapnr, ret, syscall_nr;
     //target_siginfo_t info;
@@ -458,6 +522,10 @@ void cpu_loop(CPUSPARCState *env, enum BSDType bsd_type)
 #ifndef TARGET_SPARC64
         case 0x80:
 #else
+        /* FreeBSD uses 0x141 for syscalls too */
+        case 0x141:
+            if (bsd_type != target_freebsd)
+                goto badtrap;
         case 0x100:
 #endif
             syscall_nr = env->gregs[1];
@@ -465,7 +533,7 @@ void cpu_loop(CPUSPARCState *env, enum BSDType bsd_type)
                 ret = do_freebsd_syscall(env, syscall_nr,
                                          env->regwptr[0], env->regwptr[1],
                                          env->regwptr[2], env->regwptr[3],
-                                         env->regwptr[4], env->regwptr[5]);
+                                         env->regwptr[4], env->regwptr[5], 0, 0);
             else if (bsd_type == target_netbsd)
                 ret = do_netbsd_syscall(env, syscall_nr,
                                         env->regwptr[0], env->regwptr[1],
@@ -482,6 +550,7 @@ void cpu_loop(CPUSPARCState *env, enum BSDType bsd_type)
                                          env->regwptr[4], env->regwptr[5]);
             }
             if ((unsigned int)ret >= (unsigned int)(-515)) {
+                ret = -ret;
 #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
                 env->xcc |= PSR_CARRY;
 #else
@@ -587,6 +656,9 @@ void cpu_loop(CPUSPARCState *env, enum BSDType bsd_type)
             }
             break;
         default:
+#ifdef TARGET_SPARC64
+        badtrap:
+#endif
             printf ("Unhandled trap: 0x%x\n", trapnr);
             cpu_dump_state(env, stderr, fprintf, 0);
             exit (1);
@@ -668,7 +740,7 @@ int main(int argc, char **argv)
     int gdbstub_port = 0;
     char **target_environ, **wrk;
     envlist_t *envlist = NULL;
-    enum BSDType bsd_type = target_openbsd;
+    bsd_type = target_openbsd;
 
     if (argc <= 1)
         usage();
@@ -1033,7 +1105,7 @@ int main(int argc, char **argv)
         gdbserver_start (gdbstub_port);
         gdb_handlesig(env, 0);
     }
-    cpu_loop(env, bsd_type);
+    cpu_loop(env);
     /* never exits */
     return 0;
 }