aboutsummaryrefslogtreecommitdiff
path: root/accel/tcg/translator.c
diff options
context:
space:
mode:
Diffstat (limited to 'accel/tcg/translator.c')
-rw-r--r--accel/tcg/translator.c34
1 files changed, 22 insertions, 12 deletions
diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c
index 0fd9efceba..1a6a5448c8 100644
--- a/accel/tcg/translator.c
+++ b/accel/tcg/translator.c
@@ -12,9 +12,9 @@
#include "qemu/error-report.h"
#include "exec/exec-all.h"
#include "exec/translator.h"
-#include "exec/translate-all.h"
#include "exec/plugin-gen.h"
#include "tcg/tcg-op-common.h"
+#include "internal.h"
static void gen_io_start(void)
{
@@ -147,10 +147,6 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
db->host_addr[0] = host_pc;
db->host_addr[1] = NULL;
-#ifdef CONFIG_USER_ONLY
- page_protect(pc);
-#endif
-
ops->init_disas_context(db, cpu);
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
@@ -256,22 +252,36 @@ static void *translator_access(CPUArchState *env, DisasContextBase *db,
host = db->host_addr[1];
base = TARGET_PAGE_ALIGN(db->pc_first);
if (host == NULL) {
- tb_page_addr_t phys_page =
- get_page_addr_code_hostp(env, base, &db->host_addr[1]);
+ tb_page_addr_t page0, old_page1, new_page1;
+
+ new_page1 = get_page_addr_code_hostp(env, base, &db->host_addr[1]);
/*
* If the second page is MMIO, treat as if the first page
* was MMIO as well, so that we do not cache the TB.
*/
- if (unlikely(phys_page == -1)) {
+ if (unlikely(new_page1 == -1)) {
+ tb_unlock_pages(tb);
tb_set_page_addr0(tb, -1);
return NULL;
}
- tb_set_page_addr1(tb, phys_page);
-#ifdef CONFIG_USER_ONLY
- page_protect(end);
-#endif
+ /*
+ * If this is not the first time around, and page1 matches,
+ * then we already have the page locked. Alternately, we're
+ * not doing anything to prevent the PTE from changing, so
+ * we might wind up with a different page, requiring us to
+ * re-do the locking.
+ */
+ old_page1 = tb_page_addr1(tb);
+ if (likely(new_page1 != old_page1)) {
+ page0 = tb_page_addr0(tb);
+ if (unlikely(old_page1 != -1)) {
+ tb_unlock_page1(page0, old_page1);
+ }
+ tb_set_page_addr1(tb, new_page1);
+ tb_lock_page1(page0, new_page1);
+ }
host = db->host_addr[1];
}