Signed-off-by: Timothy Edward Baldwin <t.e.baldwi...@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(-)
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 -- 2.1.4