diff mbox

[04/34] linux-user: Support for restarting system calls for x86 targets

Message ID 1441497448-32489-5-git-send-email-T.E.Baldwin99@members.leeds.ac.uk
State New
Headers show

Commit Message

Timothy Baldwin Sept. 5, 2015, 11:56 p.m. UTC
Signed-off-by: Timothy Edward Baldwin <T.E.Baldwin99@members.leeds.ac.uk>
---
 linux-user/i386/syscall.h   |  2 ++
 linux-user/main.c           | 47 ++++++++++++++++++++++++++++-----------------
 linux-user/signal.c         | 15 +++++++--------
 linux-user/syscall.c        |  2 --
 linux-user/x86_64/syscall.h |  2 ++
 5 files changed, 40 insertions(+), 28 deletions(-)

Comments

Peter Maydell Sept. 10, 2015, 6:08 p.m. UTC | #1
On 6 September 2015 at 00:56, Timothy E Baldwin
<T.E.Baldwin99@members.leeds.ac.uk> wrote:
> Signed-off-by: Timothy Edward Baldwin <T.E.Baldwin99@members.leeds.ac.uk>
> ---
>  linux-user/i386/syscall.h   |  2 ++
>  linux-user/main.c           | 47 ++++++++++++++++++++++++++++-----------------
>  linux-user/signal.c         | 15 +++++++--------
>  linux-user/syscall.c        |  2 --
>  linux-user/x86_64/syscall.h |  2 ++
>  5 files changed, 40 insertions(+), 28 deletions(-)

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM
diff mbox

Patch

diff --git a/linux-user/i386/syscall.h b/linux-user/i386/syscall.h
index 906aaac..f7d9fbe 100644
--- a/linux-user/i386/syscall.h
+++ b/linux-user/i386/syscall.h
@@ -150,3 +150,5 @@  struct target_vm86plus_struct {
 #define TARGET_MINSIGSTKSZ 2048
 #define TARGET_MLOCKALL_MCL_CURRENT 1
 #define TARGET_MLOCKALL_MCL_FUTURE  2
+
+#define TARGET_USE_ERESTARTSYS 1
diff --git a/linux-user/main.c b/linux-user/main.c
index 2c9658e..99fe591 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -274,6 +274,7 @@  void cpu_loop(CPUX86State *env)
     CPUState *cs = CPU(x86_env_get_cpu(env));
     int trapnr;
     abi_ulong pc;
+    abi_ulong ret;
     target_siginfo_t info;
 
     for(;;) {
@@ -283,28 +284,38 @@  void cpu_loop(CPUX86State *env)
         switch(trapnr) {
         case 0x80:
             /* linux syscall from int $0x80 */
-            env->regs[R_EAX] = do_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],
-                                          0, 0);
+            ret = do_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],
+                             0, 0);
+            if (ret == -TARGET_ERESTARTSYS) {
+                env->eip -= 2;
+            } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+                env->regs[R_EAX] = ret;
+            }
             break;
 #ifndef TARGET_ABI32
         case EXCP_SYSCALL:
             /* linux syscall from syscall instruction */
-            env->regs[R_EAX] = do_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],
-                                          0, 0);
+            ret = do_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],
+                             0, 0);
+            if (ret == -TARGET_ERESTARTSYS) {
+                env->eip -= 2;
+            } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+                env->regs[R_EAX] = ret;
+            }
             break;
 #endif
         case EXCP0B_NOSEG:
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 7c846c0..0186147 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -1036,7 +1036,7 @@  give_sigsegv:
 }
 
 static int
-restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
+restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc)
 {
     unsigned int err = 0;
     abi_ulong fpstate_addr;
@@ -1054,6 +1054,7 @@  restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
     env->regs[R_EBX] = tswapl(sc->ebx);
     env->regs[R_EDX] = tswapl(sc->edx);
     env->regs[R_ECX] = tswapl(sc->ecx);
+    env->regs[R_EAX] = tswapl(sc->eax);
     env->eip = tswapl(sc->eip);
 
     cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
@@ -1071,7 +1072,6 @@  restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
         cpu_x86_frstor(env, fpstate_addr, 1);
     }
 
-    *peax = tswapl(sc->eax);
     return err;
 badframe:
     return 1;
@@ -1083,7 +1083,7 @@  long do_sigreturn(CPUX86State *env)
     abi_ulong frame_addr = env->regs[R_ESP] - 8;
     target_sigset_t target_set;
     sigset_t set;
-    int eax, i;
+    int i;
 
 #if defined(DEBUG_SIGNAL)
     fprintf(stderr, "do_sigreturn\n");
@@ -1100,10 +1100,10 @@  long do_sigreturn(CPUX86State *env)
     do_sigprocmask(SIG_SETMASK, &set, NULL);
 
     /* restore registers */
-    if (restore_sigcontext(env, &frame->sc, &eax))
+    if (restore_sigcontext(env, &frame->sc))
         goto badframe;
     unlock_user_struct(frame, frame_addr, 0);
-    return eax;
+    return -TARGET_QEMU_ESIGRETURN;
 
 badframe:
     unlock_user_struct(frame, frame_addr, 0);
@@ -1116,7 +1116,6 @@  long do_rt_sigreturn(CPUX86State *env)
     abi_ulong frame_addr;
     struct rt_sigframe *frame;
     sigset_t set;
-    int eax;
 
     frame_addr = env->regs[R_ESP] - 4;
     if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
@@ -1125,7 +1124,7 @@  long do_rt_sigreturn(CPUX86State *env)
     target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
     do_sigprocmask(SIG_SETMASK, &set, NULL);
 
-    if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax)) {
+    if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
         goto badframe;
     }
 
@@ -1135,7 +1134,7 @@  long do_rt_sigreturn(CPUX86State *env)
     }
 
     unlock_user_struct(frame, frame_addr, 0);
-    return eax;
+    return -TARGET_QEMU_ESIGRETURN;
 
 badframe:
     unlock_user_struct(frame, frame_addr, 0);
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 4e40dc6..04c91fb 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -6601,12 +6601,10 @@  abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 #ifdef TARGET_NR_sigreturn
     case TARGET_NR_sigreturn:
-        /* NOTE: ret is eax, so not transcoding must be done */
         ret = do_sigreturn(cpu_env);
         break;
 #endif
     case TARGET_NR_rt_sigreturn:
-        /* NOTE: ret is eax, so not transcoding must be done */
         ret = do_rt_sigreturn(cpu_env);
         break;
     case TARGET_NR_sethostname:
diff --git a/linux-user/x86_64/syscall.h b/linux-user/x86_64/syscall.h
index 88b3c3f..d41a93a 100644
--- a/linux-user/x86_64/syscall.h
+++ b/linux-user/x86_64/syscall.h
@@ -100,3 +100,5 @@  struct target_msqid64_ds {
 #define TARGET_MINSIGSTKSZ 2048
 #define TARGET_MLOCKALL_MCL_CURRENT 1
 #define TARGET_MLOCKALL_MCL_FUTURE  2
+
+#define TARGET_USE_ERESTARTSYS 1