[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v2 2/4] target/s390x: Make translator stop before the end of a pa
From: |
Ilya Leoshkevich |
Subject: |
[PATCH v2 2/4] target/s390x: Make translator stop before the end of a page |
Date: |
Fri, 5 Aug 2022 18:09:12 +0200 |
Right now translator stops right *after* the end of a page, which
breaks reporting of fault locations when the last instruction of a
multi-insn translation block crosses a page boundary.
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
include/exec/translator.h | 10 ++++++++++
target/s390x/tcg/translate.c | 35 ++++++++++++++++++++---------------
2 files changed, 30 insertions(+), 15 deletions(-)
diff --git a/include/exec/translator.h b/include/exec/translator.h
index 7db6845535..d27f8c33b6 100644
--- a/include/exec/translator.h
+++ b/include/exec/translator.h
@@ -187,4 +187,14 @@ FOR_EACH_TRANSLATOR_LD(GEN_TRANSLATOR_LD)
#undef GEN_TRANSLATOR_LD
+/*
+ * Return whether addr is on the same page as where disassembly started.
+ * Translators can use this to enforce the rule that only single-insn
+ * translation blocks are allowed to cross page boundaries.
+ */
+static inline bool is_same_page(DisasContextBase *db, target_ulong addr)
+{
+ return ((addr ^ db->pc_first) & TARGET_PAGE_MASK) == 0;
+}
+
#endif /* EXEC__TRANSLATOR_H */
diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c
index e2ee005671..0cd0c932fb 100644
--- a/target/s390x/tcg/translate.c
+++ b/target/s390x/tcg/translate.c
@@ -6305,14 +6305,13 @@ static void extract_field(DisasFields *o, const
DisasField *f, uint64_t insn)
o->c[f->indexC] = r;
}
-/* Lookup the insn at the current PC, extracting the operands into O and
- returning the info struct for the insn. Returns NULL for invalid insn. */
+/* Lookup the insn at the current PC, filling the info struct. */
-static const DisasInsn *extract_insn(CPUS390XState *env, DisasContext *s)
+static DisasJumpType extract_insn(CPUS390XState *env, DisasContext *s,
+ const DisasInsn **info)
{
uint64_t insn, pc = s->base.pc_next;
int op, op2, ilen;
- const DisasInsn *info;
if (unlikely(s->ex_value)) {
/* Drop the EX data now, so that it's clear on exception paths. */
@@ -6325,9 +6324,13 @@ static const DisasInsn *extract_insn(CPUS390XState *env,
DisasContext *s)
ilen = s->ex_value & 0xf;
op = insn >> 56;
} else {
+ assert(s->base.num_insns == 1 || is_same_page(&s->base, pc));
insn = ld_code2(env, s, pc);
op = (insn >> 8) & 0xff;
ilen = get_ilen(op);
+ if (s->base.num_insns > 1 && !is_same_page(&s->base, pc + ilen - 1)) {
+ return DISAS_TOO_MANY;
+ }
switch (ilen) {
case 2:
insn = insn << 48;
@@ -6394,19 +6397,19 @@ static const DisasInsn *extract_insn(CPUS390XState
*env, DisasContext *s)
s->fields.op2 = op2;
/* Lookup the instruction. */
- info = lookup_opc(op << 8 | op2);
- s->insn = info;
+ *info = lookup_opc(op << 8 | op2);
+ s->insn = *info;
/* If we found it, extract the operands. */
- if (info != NULL) {
- DisasFormat fmt = info->fmt;
+ if (*info != NULL) {
+ DisasFormat fmt = (*info)->fmt;
int i;
for (i = 0; i < NUM_C_FIELD; ++i) {
extract_field(&s->fields, &format_info[fmt].op[i], insn);
}
}
- return info;
+ return DISAS_NEXT;
}
static bool is_afp_reg(int reg)
@@ -6423,12 +6426,17 @@ static bool is_fp_pair(int reg)
static DisasJumpType translate_one(CPUS390XState *env, DisasContext *s)
{
const DisasInsn *insn;
- DisasJumpType ret = DISAS_NEXT;
+ DisasJumpType ret;
DisasOps o = {};
bool icount = false;
/* Search for the insn in the table. */
- insn = extract_insn(env, s);
+ ret = extract_insn(env, s, &insn);
+
+ /* This is a subsequent insn that crosses a page boundary. */
+ if (ret == DISAS_TOO_MANY) {
+ goto out;
+ }
/* Update insn_start now that we know the ILEN. */
tcg_set_insn_start_param(s->insn_start, 2, s->ilen);
@@ -6616,10 +6624,7 @@ static void s390x_tr_translate_insn(DisasContextBase
*dcbase, CPUState *cs)
dc->base.is_jmp = translate_one(env, dc);
if (dc->base.is_jmp == DISAS_NEXT) {
- uint64_t page_start;
-
- page_start = dc->base.pc_first & TARGET_PAGE_MASK;
- if (dc->base.pc_next - page_start >= TARGET_PAGE_SIZE || dc->ex_value)
{
+ if (!is_same_page(dcbase, dc->base.pc_next) || dc->ex_value) {
dc->base.is_jmp = DISAS_TOO_MANY;
}
}
--
2.35.3