aboutsummaryrefslogtreecommitdiff
path: root/target/i386/seg_helper.c
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2017-03-07 12:37:36 +0100
committerAlex Bennée <alex.bennee@linaro.org>2017-03-09 10:41:48 +0000
commit10cde894b63146139f981857e4eedf756fa53dcb (patch)
tree2d3de35923c5a173450da4615950354e84e1c2db /target/i386/seg_helper.c
parentd394698d73836d1c50545bdb32dc58d09708fcfb (diff)
target-i386: defer VMEXIT to do_interrupt
Paths through the softmmu code during code generation now need to be audited to check for double locking of tb_lock. In particular, VMEXIT can take tb_lock through cpu_vmexit -> cpu_x86_update_cr4 -> tlb_flush. To avoid this, split VMEXIT delivery in two parts, similar to what is done with exceptions. cpu_vmexit only records the VMEXIT exit code and information, and cc->do_interrupt can then deliver it when it is safe to take the lock. Reported-by: Alexander Boettcher <alexander.boettcher@genode-labs.com> Suggested-by: Richard Henderson <rth@twiddle.net> Tested-by: Alexander Boettcher <alexander.boettcher@genode-labs.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Richard Henderson <rth@twiddle.net>
Diffstat (limited to 'target/i386/seg_helper.c')
-rw-r--r--target/i386/seg_helper.c20
1 files changed, 11 insertions, 9 deletions
diff --git a/target/i386/seg_helper.c b/target/i386/seg_helper.c
index 5c845dc25c..0374031ea2 100644
--- a/target/i386/seg_helper.c
+++ b/target/i386/seg_helper.c
@@ -1297,15 +1297,17 @@ void x86_cpu_do_interrupt(CPUState *cs)
/* successfully delivered */
env->old_exception = -1;
#else
- /* simulate a real cpu exception. On i386, it can
- trigger new exceptions, but we do not handle
- double or triple faults yet. */
- do_interrupt_all(cpu, cs->exception_index,
- env->exception_is_int,
- env->error_code,
- env->exception_next_eip, 0);
- /* successfully delivered */
- env->old_exception = -1;
+ if (cs->exception_index >= EXCP_VMEXIT) {
+ assert(env->old_exception == -1);
+ do_vmexit(env, cs->exception_index - EXCP_VMEXIT, env->error_code);
+ } else {
+ do_interrupt_all(cpu, cs->exception_index,
+ env->exception_is_int,
+ env->error_code,
+ env->exception_next_eip, 0);
+ /* successfully delivered */
+ env->old_exception = -1;
+ }
#endif
}