aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJincheng Miao <jmiao@redhat.com>2014-08-08 11:56:54 +0800
committerRiku Voipio <riku.voipio@linaro.org>2014-08-22 15:06:33 +0300
commit47575997be9e0cae44a4fcaecbd172fec3746c96 (patch)
tree4f5e143e0be83f4102e34da512d3727bcaa22be7
parent0b2effd744471adea1cc82966df8a54fd6afa200 (diff)
downloadqemu-arm-47575997be9e0cae44a4fcaecbd172fec3746c96.tar.gz
linux-user: Fix syscall instruction usermode emulation on X86_64
Currently syscall instruction is buggy on user mode X86_64, the EIP is updated after do_syscall(), that is too late for clone(). Because clone() will create a thread at the env->EIP (the address of syscall insn), and then child thread enters do_syscall() again, that is not expected. Sometimes it is tragic. User mode syscall insn emulation is not used MSR, so the action should be same to INT 0x80. INT 0x80 will update EIP in do_interrupt(), ditto for syscall() for consistency. Signed-off-by: Jincheng Miao <jmiao@redhat.com> Reviewed-by: Richard Henderson <rth@twiddle.net> Signed-off-by: Riku Voipio <riku.voipio@linaro.org>
-rw-r--r--linux-user/main.c1
-rw-r--r--target-i386/seg_helper.c4
2 files changed, 2 insertions, 3 deletions
diff --git a/linux-user/main.c b/linux-user/main.c
index b453a39853..472a16d2db 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -309,7 +309,6 @@ void cpu_loop(CPUX86State *env)
env->regs[8],
env->regs[9],
0, 0);
- env->eip = env->exception_next_eip;
break;
#endif
case EXCP0B_NOSEG:
diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c
index 2d970d0cb9..13eefbac3b 100644
--- a/target-i386/seg_helper.c
+++ b/target-i386/seg_helper.c
@@ -1127,8 +1127,8 @@ static void do_interrupt_user(CPUX86State *env, int intno, int is_int,
/* Since we emulate only user space, we cannot do more than
exiting the emulation with the suitable exception and error
- code */
- if (is_int) {
+ code. So update EIP for INT 0x80 and EXCP_SYSCALL. */
+ if (is_int || intno == EXCP_SYSCALL) {
env->eip = next_eip;
}
}