]> Git Repo - qemu.git/commitdiff
alpha-linux-user: Fix sigprocmask.
authorRichard Henderson <[email protected]>
Mon, 3 May 2010 17:07:55 +0000 (10:07 -0700)
committerAurelien Jarno <[email protected]>
Fri, 21 May 2010 16:22:21 +0000 (16:22 +0000)
Alpha passes oldset by value in a register, and returns the newset
as the return value; as compared to the standard implementation in
which both are passed by reference.  This requires being able to
distinguish negative return values that are not errors.  Do this in
the same way as the Alpha Linux kernel, by storing a zero in V0 in
the implementation of the syscall.

At the same time, fix a think-o in the regular sigprocmask path in
which we passed the target, rather than the host, HOW value.

Signed-off-by: Richard Henderson <[email protected]>
Signed-off-by: Aurelien Jarno <[email protected]>
linux-user/main.c
linux-user/syscall.c

index b158bbc296487bfcc72759b5e88596a4253f4b48..5027a6d99402bfdc40eec2153ee86b8794980f73 100644 (file)
@@ -2499,8 +2499,15 @@ void cpu_loop (CPUState *env)
                                     env->ir[IR_A0], env->ir[IR_A1],
                                     env->ir[IR_A2], env->ir[IR_A3],
                                     env->ir[IR_A4], env->ir[IR_A5]);
-                if (trapnr != TARGET_NR_sigreturn
-                    && trapnr != TARGET_NR_rt_sigreturn) {
+                if (trapnr == TARGET_NR_sigreturn
+                    || trapnr == TARGET_NR_rt_sigreturn) {
+                    break;
+                }
+                /* Syscall writes 0 to V0 to bypass error check, similar
+                   to how this is handled internal to Linux kernel.  */
+                if (env->ir[IR_V0] == 0) {
+                    env->ir[IR_V0] = sysret;
+                } else {
                     env->ir[IR_V0] = (sysret < 0 ? -sysret : sysret);
                     env->ir[IR_A3] = (sysret < 0);
                 }
index fb18b24d2b0c6a3750fa5235f11443877f1da586..bca8f70f2cfca67860280faeacae39fe542ae623 100644 (file)
@@ -4983,11 +4983,41 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 #ifdef TARGET_NR_sigprocmask
     case TARGET_NR_sigprocmask:
         {
-            int how = arg1;
+#if defined(TARGET_ALPHA)
+            sigset_t set, oldset;
+            abi_ulong mask;
+            int how;
+
+            switch (arg1) {
+            case TARGET_SIG_BLOCK:
+                how = SIG_BLOCK;
+                break;
+            case TARGET_SIG_UNBLOCK:
+                how = SIG_UNBLOCK;
+                break;
+            case TARGET_SIG_SETMASK:
+                how = SIG_SETMASK;
+                break;
+            default:
+                ret = -TARGET_EINVAL;
+                goto fail;
+            }
+            mask = arg2;
+            target_to_host_old_sigset(&set, &mask);
+
+            ret = get_errno(sigprocmask(how, &set, &oldset));
+
+            if (!is_error(ret)) {
+                host_to_target_old_sigset(&mask, &oldset);
+                ret = mask;
+                ((CPUAlphaState *)cpu_env)->[IR_V0] = 0; /* force no error */
+            }
+#else
             sigset_t set, oldset, *set_ptr;
+            int how;
 
             if (arg2) {
-                switch(how) {
+                switch (arg1) {
                 case TARGET_SIG_BLOCK:
                     how = SIG_BLOCK;
                     break;
@@ -5010,13 +5040,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                 how = 0;
                 set_ptr = NULL;
             }
-            ret = get_errno(sigprocmask(arg1, set_ptr, &oldset));
+            ret = get_errno(sigprocmask(how, set_ptr, &oldset));
             if (!is_error(ret) && arg3) {
                 if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
                     goto efault;
                 host_to_target_old_sigset(p, &oldset);
                 unlock_user(p, arg3, sizeof(target_sigset_t));
             }
+#endif
         }
         break;
 #endif
This page took 0.033994 seconds and 4 git commands to generate.