aboutsummaryrefslogtreecommitdiff
path: root/include/exec
diff options
context:
space:
mode:
authorIlya Leoshkevich <iii@linux.ibm.com>2021-08-05 22:48:35 +0200
committerRichard Henderson <richard.henderson@linaro.org>2021-09-14 12:00:20 -0700
commitf025692c992c1ed6cc54ac2802cff14e9052c0d3 (patch)
tree01931a3394d5f38e9f237de94ac0b82fcce8ff22 /include/exec
parent4e116893c6079b51efdc9e226be3f1a530f47f5e (diff)
accel/tcg: Clear PAGE_WRITE before translation
translate_insn() implementations fetch instruction bytes piecemeal, which can cause qemu-user to generate inconsistent translations if another thread modifies them concurrently [1]. Fix by making pages containing translated instruction non-writable right before loading instruction bytes from them. [1] https://lists.nongnu.org/archive/html/qemu-devel/2021-08/msg00644.html Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Message-Id: <20210805204835.158918-1-iii@linux.ibm.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'include/exec')
-rw-r--r--include/exec/translate-all.h1
-rw-r--r--include/exec/translator.h39
2 files changed, 24 insertions, 16 deletions
diff --git a/include/exec/translate-all.h b/include/exec/translate-all.h
index a557b4e2bb..9f646389af 100644
--- a/include/exec/translate-all.h
+++ b/include/exec/translate-all.h
@@ -33,6 +33,7 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end);
void tb_check_watchpoint(CPUState *cpu, uintptr_t retaddr);
#ifdef CONFIG_USER_ONLY
+void page_protect(tb_page_addr_t page_addr);
int page_unprotect(target_ulong address, uintptr_t pc);
#endif
diff --git a/include/exec/translator.h b/include/exec/translator.h
index 6c054e8d05..9bc46eda59 100644
--- a/include/exec/translator.h
+++ b/include/exec/translator.h
@@ -23,6 +23,7 @@
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
#include "exec/plugin-gen.h"
+#include "exec/translate-all.h"
#include "tcg/tcg.h"
@@ -74,6 +75,17 @@ typedef struct DisasContextBase {
int num_insns;
int max_insns;
bool singlestep_enabled;
+#ifdef CONFIG_USER_ONLY
+ /*
+ * Guest address of the last byte of the last protected page.
+ *
+ * Pages containing the translated instructions are made non-writable in
+ * order to achieve consistency in case another thread is modifying the
+ * code while translate_insn() fetches the instruction bytes piecemeal.
+ * Such writer threads are blocked on mmap_lock() in page_unprotect().
+ */
+ target_ulong page_protect_end;
+#endif
} DisasContextBase;
/**
@@ -156,28 +168,23 @@ bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest);
*/
#define GEN_TRANSLATOR_LD(fullname, type, load_fn, swap_fn) \
- static inline type \
- fullname ## _swap(CPUArchState *env, DisasContextBase *dcbase, \
- abi_ptr pc, bool do_swap) \
- { \
- type ret = load_fn(env, pc); \
- if (do_swap) { \
- ret = swap_fn(ret); \
- } \
- plugin_insn_append(&ret, sizeof(ret)); \
- return ret; \
- } \
+ type fullname ## _swap(CPUArchState *env, DisasContextBase *dcbase, \
+ abi_ptr pc, bool do_swap); \
static inline type fullname(CPUArchState *env, \
DisasContextBase *dcbase, abi_ptr pc) \
{ \
return fullname ## _swap(env, dcbase, pc, false); \
}
-GEN_TRANSLATOR_LD(translator_ldub, uint8_t, cpu_ldub_code, /* no swap */)
-GEN_TRANSLATOR_LD(translator_ldsw, int16_t, cpu_ldsw_code, bswap16)
-GEN_TRANSLATOR_LD(translator_lduw, uint16_t, cpu_lduw_code, bswap16)
-GEN_TRANSLATOR_LD(translator_ldl, uint32_t, cpu_ldl_code, bswap32)
-GEN_TRANSLATOR_LD(translator_ldq, uint64_t, cpu_ldq_code, bswap64)
+#define FOR_EACH_TRANSLATOR_LD(F) \
+ F(translator_ldub, uint8_t, cpu_ldub_code, /* no swap */) \
+ F(translator_ldsw, int16_t, cpu_ldsw_code, bswap16) \
+ F(translator_lduw, uint16_t, cpu_lduw_code, bswap16) \
+ F(translator_ldl, uint32_t, cpu_ldl_code, bswap32) \
+ F(translator_ldq, uint64_t, cpu_ldq_code, bswap64)
+
+FOR_EACH_TRANSLATOR_LD(GEN_TRANSLATOR_LD)
+
#undef GEN_TRANSLATOR_LD
#endif /* EXEC__TRANSLATOR_H */