All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 1/2] target/i386/tcg: fix EIP truncation for wrapping 16-bit near branches
@ 2026-09-10 18:05 Paul Galbraith
  2026-09-10 18:05 ` [PATCH v2 2/2] tests/tcg/i386: add regression test " Paul Galbraith
  0 siblings, 1 reply; 2+ messages in thread
From: Paul Galbraith @ 2026-09-10 18:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: Paolo Bonzini, Richard Henderson, Paul Galbraith

A 16-bit near branch must truncate EIP to 16 bits. gen_jmp_rel() skips
that when the target lands on the same guest page as the translation
block, taking a branch that stayed on the page as proof the addition did
not wrap.

That holds for the linear address, but EIP wraps at 0x10000, and the two
only coincide when cs_base is page aligned. Otherwise two linear
addresses can share a page while the EIP values either side of them
straddle 0x10000, and a CALL or JMP rel16 runs with EIP untruncated.

Compare the source and destination EIP pages instead. It has to stay a
page test rather than a check on the EIP values: a CF_PCREL TB is not
keyed on the virtual PC and records only its page offset, so the same TB
can later run with EIP shifted by whole pages.

One case is left over: a 16-bit segment with a limit above 0xffff (D/B
clear, G set), where EIP can start out above the mask. The data16 guard
keys on D/B and not the limit, so it does not catch that either. Closing
it needs the limit in the TB key.

64-bit mode is unaffected, as no masking is applied there.

Signed-off-by: Paul Galbraith <paul@galbraiths.ca>
---
v1: https://patchew.org/QEMU/6c5fca8e-b9f4-48a0-a070-42f10d1f942b@app.fastmail.com/

Changes in v2:
 - Different approach. v1 required cs_base to be page aligned before allowing
   goto_tb, and dropped the data16-in-code32 guard on the assumption that the
   new condition subsumed it. It does not: that guard is there for a separate
   case, EIP starting out above the mask, so v1 would have swapped one problem
   for another. v2 compares source and destination EIP pages and leaves the
   guard alone.
 - Split into two patches; the regression test is now patch 2.

 target/i386/tcg/translate.c | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index d8de290acb..6d3c929eee 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -2025,12 +2025,24 @@ static void gen_jmp_rel(DisasContext *s, MemOp ot, int diff, int tb_num)
 
     if (tb_cflags(s->base.tb) & CF_PCREL) {
         tcg_gen_addi_tl(cpu_eip, cpu_eip, new_pc - s->pc_save);
+
+        /*
+         * True if a wrap cannot be ruled out: the source and destination EIP
+         * are in different EIP pages.  If they share one, the addition cannot
+         * leave [0, mask] on any rerun of this TB, which only ever shifts EIP
+         * by whole pages.
+         */
+        bool eip_may_wrap = !CODE64(s) &&
+            (((s->pc_save - s->cs_base) ^ (new_pc - s->cs_base))
+             & TARGET_PAGE_MASK) != 0;
+
         /*
-         * If we can prove the branch does not leave the page and we have
-         * no extra masking to apply (data16 branch in code32, see above),
-         * then we have also proven that the addition does not wrap.
+         * If we can prove the branch does not leave the page, does not leave
+         * its EIP page, and we have no extra masking to apply (data16 branch
+         * in code32, see above), then the addition does not wrap.
          */
-        if (!use_goto_tb || !translator_is_same_page(&s->base, new_pc)) {
+        if (!use_goto_tb || !translator_is_same_page(&s->base, new_pc)
+                || eip_may_wrap) {
             tcg_gen_andi_tl(cpu_eip, cpu_eip, mask);
             use_goto_tb = false;
         }
-- 
2.54.0.windows.1



^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-09-10 18:06 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-10 18:05 [PATCH v2 1/2] target/i386/tcg: fix EIP truncation for wrapping 16-bit near branches Paul Galbraith
2026-09-10 18:05 ` [PATCH v2 2/2] tests/tcg/i386: add regression test " Paul Galbraith

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.