aboutsummaryrefslogtreecommitdiff
path: root/accel
diff options
context:
space:
mode:
authorPavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>2018-02-27 12:53:38 +0300
committerPaolo Bonzini <pbonzini@redhat.com>2018-03-12 17:10:38 +0100
commit0790f86861079b1932679d0f011e431aaf4ee9e2 (patch)
tree849c0a038c8cd9d51e24442b939bafaa8e2d0324 /accel
parent7273db9d28d5e1b7a6c202a5054861c1f0bcc446 (diff)
tcg: fix cpu_io_recompile
cpu_io_recompile() function was broken by the commit 9b990ee5a3cc6aa38f81266fb0c6ef37a36c45b9. Instead of regenerating the block starting from PC of the original block, it just set the instruction counter for TCG. In most cases this was unnoticed, but in icount mode there was an exception for incorrect usage of CF_LAST_IO flag. This patch recovers recompilation of the original block and also configures translation for executing single IO instruction which caused a recompilation. Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru> Message-Id: <20180227095338.1060.27385.stgit@pasha-VirtualBox> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
Diffstat (limited to 'accel')
-rw-r--r--accel/tcg/translate-all.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index 67795cd78c..5ad1b919bc 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -1728,7 +1728,8 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
CPUArchState *env = cpu->env_ptr;
#endif
TranslationBlock *tb;
- uint32_t n;
+ uint32_t n, flags;
+ target_ulong pc, cs_base;
tb_lock();
tb = tb_find_pc(retaddr);
@@ -1766,8 +1767,14 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
cpu_abort(cpu, "TB too big during recompile");
}
- /* Adjust the execution state of the next TB. */
- cpu->cflags_next_tb = curr_cflags() | CF_LAST_IO | n;
+ pc = tb->pc;
+ cs_base = tb->cs_base;
+ flags = tb->flags;
+ tb_phys_invalidate(tb, -1);
+
+ /* Execute one IO instruction without caching
+ instead of creating large TB. */
+ cpu->cflags_next_tb = curr_cflags() | CF_LAST_IO | CF_NOCACHE | 1;
if (tb->cflags & CF_NOCACHE) {
if (tb->orig_tb) {
@@ -1778,6 +1785,11 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
tb_remove(tb);
}
+ /* Generate new TB instead of the current one. */
+ /* FIXME: In theory this could raise an exception. In practice
+ we have already translated the block once so it's probably ok. */
+ tb_gen_code(cpu, pc, cs_base, flags, curr_cflags() | CF_LAST_IO | n);
+
/* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not
* the first in the TB) then we end up generating a whole new TB and
* repeating the fault, which is horribly inefficient.