From ab0d62b99fff85893baadd50c12bdcf3c4867488 Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Sun, 19 Nov 2023 20:17:36 +0100 Subject: [PATCH] Fixed a bug where the translator was using an incorrect physical address when the next instruction started at a page boundary --- lib86cpu/core/emitter/x64/jit.cpp | 2 +- lib86cpu/core/internal.h | 17 +++++++++-------- lib86cpu/core/translate.cpp | 6 +++++- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/lib86cpu/core/emitter/x64/jit.cpp b/lib86cpu/core/emitter/x64/jit.cpp index ff87d65..a84dd0d 100644 --- a/lib86cpu/core/emitter/x64/jit.cpp +++ b/lib86cpu/core/emitter/x64/jit.cpp @@ -733,7 +733,7 @@ lc86_jit::gen_tc_epilogue() { // update the eip if we stopped decoding without a terminating instr if (m_cpu->translate_next == 1) { - assert((DISAS_FLG_PAGE_CROSS | DISAS_FLG_ONE_INSTR) != 0); + assert((m_cpu->disas_ctx.flags & (DISAS_FLG_PAGE_CROSS | DISAS_FLG_PAGE_CROSS_NEXT | DISAS_FLG_ONE_INSTR)) != 0); assert((m_cpu->tc->flags & TC_FLG_LINK_MASK) == 0); MOV(MEMD32(RCX, CPU_CTX_EIP), m_cpu->virt_pc - m_cpu->cpu_ctx.regs.cs_hidden.base); diff --git a/lib86cpu/core/internal.h b/lib86cpu/core/internal.h index e9f8727..31924b8 100644 --- a/lib86cpu/core/internal.h +++ b/lib86cpu/core/internal.h @@ -88,14 +88,15 @@ void JIT_API tlb_invalidate_(cpu_ctx_t *cpu_ctx, addr_t addr); #define MMU_SET_CODE (1 << 4) // disassembly context flags -#define DISAS_FLG_CS32 (1 << 0) -#define DISAS_FLG_SS32 (1 << 1) -#define DISAS_FLG_PAGE_CROSS (1 << 2) -#define DISAS_FLG_INHIBIT_INT (1 << 3) -#define DISAS_FLG_PE HFLG_PE_MODE // (1 << 4) -#define DISAS_FLG_FETCH_FAULT DISAS_FLG_PAGE_CROSS // (1 << 2) -#define DISAS_FLG_DBG_FAULT DISAS_FLG_PAGE_CROSS // (1 << 2) -#define DISAS_FLG_ONE_INSTR CPU_DISAS_ONE // (1 << 7) +#define DISAS_FLG_CS32 (1 << 0) +#define DISAS_FLG_SS32 (1 << 1) +#define DISAS_FLG_PAGE_CROSS (1 << 2) +#define DISAS_FLG_INHIBIT_INT (1 << 3) +#define DISAS_FLG_PAGE_CROSS_NEXT (1 << 5) +#define DISAS_FLG_PE HFLG_PE_MODE // (1 << 4) +#define DISAS_FLG_FETCH_FAULT DISAS_FLG_PAGE_CROSS // (1 << 2) +#define DISAS_FLG_DBG_FAULT DISAS_FLG_PAGE_CROSS // (1 << 2) +#define DISAS_FLG_ONE_INSTR CPU_DISAS_ONE // (1 << 7) // tc struct flags/offsets #define TC_JMP_DST_PC 0 diff --git a/lib86cpu/core/translate.cpp b/lib86cpu/core/translate.cpp index 028909e..39acc6b 100644 --- a/lib86cpu/core/translate.cpp +++ b/lib86cpu/core/translate.cpp @@ -909,8 +909,12 @@ cpu_translate(cpu_t *cpu) if (ZYAN_SUCCESS(status)) { // successfully decoded + // NOTE: the second OR for disas_ctx->flags is to handle the edge case where the last byte of the current instructions ends exactly at a page boundary. In this case, + // the current block can be added to the code cache (so DISAS_FLG_PAGE_CROSS should not be set), but the translation of this block must terminate now (so + // DISAS_FLG_PAGE_CROSS_NEXT should be set) cpu->instr_bytes = instr.i.length; disas_ctx->flags |= ((disas_ctx->virt_pc & ~PAGE_MASK) != ((disas_ctx->virt_pc + cpu->instr_bytes - 1) & ~PAGE_MASK)) << 2; + disas_ctx->flags |= ((disas_ctx->virt_pc & ~PAGE_MASK) != ((disas_ctx->virt_pc + cpu->instr_bytes) & ~PAGE_MASK)) << 5; disas_ctx->pc += cpu->instr_bytes; disas_ctx->virt_pc += cpu->instr_bytes; @@ -1572,7 +1576,7 @@ cpu_translate(cpu_t *cpu) cpu->virt_pc += cpu->instr_bytes; cpu->tc->size += cpu->instr_bytes; - } while ((cpu->translate_next | (disas_ctx->flags & (DISAS_FLG_PAGE_CROSS | DISAS_FLG_ONE_INSTR))) == 1); + } while ((cpu->translate_next | (disas_ctx->flags & (DISAS_FLG_PAGE_CROSS | DISAS_FLG_ONE_INSTR | DISAS_FLG_PAGE_CROSS_NEXT))) == 1); } uint32_t