From 438359726b924b03774786f08951ca73d2192da9 Mon Sep 17 00:00:00 2001 From: Dylan Neve Date: Thu, 22 Oct 2026 20:25:05 +0100 Subject: [PATCH] target/arm, tcg/aarch64: native-int covers MRS of plain system-register fields (TPIDR_EL0, TPIDRRO_EL0) A system-register read with no access check, read function, constant or I/O flag (at EL0: TPIDR_EL0 and TPIDRRO_EL0, iOS's thread pointers) is a 64-bit load from the CPU state. It becomes a SIT_LDENV op instead of ending the native-int region, provided the instruction has emitted no TCG op before reaching that point. native_int_check.S test 7 reads both in the middle of ALU code. Co-Authored-By: Claude Opus 5.5 --- hw/arm/tests/native_int_check.S | 17 +++++++++++++++++ include/tcg/tcg-sit.h | 2 ++ target/arm/tcg/translate-a64.c | 22 ++++++++++++++++++++++ tcg/aarch64/tcg-target-sit.c.inc | 10 ++++++++++ 4 files changed, 51 insertions(+) diff --git a/hw/arm/tests/native_int_check.S b/hw/arm/tests/native_int_check.S index f2fc4a7f21..bdc584b489 100644 --- a/hw/arm/tests/native_int_check.S +++ b/hw/arm/tests/native_int_check.S @@ -13,6 +13,8 @@ * 4 x18, x29 and x30 as ordinary operands and load destinations * 5 NZCV set before a page-crossing (slow-path) load and store and * consumed after them + * 7 MRS TPIDR_EL0 / TPIDRRO_EL0 (plain field reads) in the middle of + * ALU code, after MSR TPIDR_EL0 at EL0 and TPIDRRO_EL0 set at EL1 * 6 a store over code later in the same block (the store's slow * path invalidates the TB being executed), then the architectural * DC CVAU/IC IVAU/ISB sequence: registers and NZCV written before @@ -124,6 +126,8 @@ _start: dsb ish isb + ldr x0, =0x7070707070707070 + msr tpidrro_el0, x0 ldr x0, =BUF msr sp_el0, x0 adr x0, el0_main @@ -303,6 +307,19 @@ fault2: CHK x15, 0x1111 - 0x2222, 6 CHK x17, 1, 6 + /* 7: TLS register reads in the middle of a block */ + LI x0, 0x0123456789abcdef + msr tpidr_el0, x0 + movz x1, #7 + mrs x2, tpidr_el0 + add x3, x2, x1 + mrs x4, tpidrro_el0 + eor x5, x4, x3 + mrs x6, tpidr_el0 + CHK x3, 0x0123456789abcdef + 7, 7 + CHK x5, 0x7070707070707070 ^ (0x0123456789abcdef + 7), 7 + CHK x6, 0x0123456789abcdef, 7 + svc #0 /* copied to CODE; x11 = the new instruction, x12 = where it goes */ diff --git a/include/tcg/tcg-sit.h b/include/tcg/tcg-sit.h index 837f50eb95..1c6d437e37 100644 --- a/include/tcg/tcg-sit.h +++ b/include/tcg/tcg-sit.h @@ -51,6 +51,8 @@ typedef enum SitKind SIT_BCOND, SIT_CBZ, SIT_TBZ, + /* rt = the 64-bit CPU state field at offset imm (a system register read with no side effects). */ + SIT_LDENV, } SitKind; /* SitInsn.mode: addressing mode of a load or store. */ diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index fe15b14781..65f21d3a93 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -564,6 +564,23 @@ static SitInsn* sit_ldst(DisasContext* s, SitKind kind, int rt, int rt2, int rn, return si; } +/* + * MRS of a system register that is a plain 64-bit field with no access + * check, read function or I/O (e.g. TPIDR_EL0, TPIDRRO_EL0): a load from + * the CPU state. Only if this insn has not emitted TCG ops yet. + */ +static bool sit_ldenv(DisasContext* s, int rt, int ofs) +{ + SitInsn* si; + + if (!sit_admit(s, 0) || tcg_last_op() != s->base.insn_start || ofs < 0 || (ofs & 7)) { return false; } + si = sit_new(s, SIT_LDENV); + si->rt = sit_reg(rt, false); + si->imm = ofs; + sit_emit(s, si); + return true; +} + /* A conditional branch to @l (taken path): ends the region. */ static void sit_brcond(DisasContext* s, SitInsn* si, TCGLabel* l) { @@ -2559,6 +2576,11 @@ static void handle_sys(DisasContext* s, bool isread, unsigned int op0, unsigned default: tcg_debug_assert_not_reached(); } + if (isread && !(ri->type & (ARM_CP_IO | ARM_CP_CONST)) && !ri->readfn && !tcg_ri && + sit_ldenv(s, rt, cpreg_field_offset(s, ri))) { + return; + } + if (ri->type & ARM_CP_IO) { /* I/O operations must end the TB here (whether read or write) */ need_exit_tb = translator_io_start(&s->base); diff --git a/tcg/aarch64/tcg-target-sit.c.inc b/tcg/aarch64/tcg-target-sit.c.inc index 5abce5d9dd..ff74a144bc 100644 --- a/tcg/aarch64/tcg-target-sit.c.inc +++ b/tcg/aarch64/tcg-target-sit.c.inc @@ -297,6 +297,15 @@ static void sit_copy(TCGContext* s, const SitInsn* si) if (si->nzcv & SIT_NZCV_W) { s->sit->m.nzcv = SIT_FL_DIRTY; } } +static void sit_ldenv(TCGContext* s, const SitInsn* si) +{ + TCGReg rd = sit_def(s, si->rt, sit_bit(si->rt)); + + if (rd == TCG_REG_XZR) { return; } + tcg_out_ldst(s, I3312_LDRX, rd, TCG_AREG0, si->imm, 3); + sit_dirty(s, si->rt); +} + static void sit_addpc(TCGContext* s, const SitInsn* si) { TCGReg rd = sit_def(s, si->rt, sit_bit(si->rt)); @@ -473,6 +482,7 @@ static void tcg_out_sit(TCGContext* s, const SitInsn* si, TCGLabel* l) switch (si->kind) { case SIT_COPY : sit_copy(s, si); break; case SIT_ADDPC: sit_addpc(s, si); break; + case SIT_LDENV: sit_ldenv(s, si); break; case SIT_LD : case SIT_ST : case SIT_LDP :