diff --git a/.gitignore b/.gitignore index bd2496358..f58566ed7 100644 --- a/.gitignore +++ b/.gitignore @@ -1890,6 +1890,7 @@ /none/tests/arm64/ldxp_stxp /none/tests/arm64/integer /none/tests/arm64/memory_test +/none/tests/arm64/mrs_id_regs /none/tests/arm64/simd_dotprod /none/tests/arm64/simd_v81 /none/tests/arm64/sha512_v82 diff --git a/CODSPEED-CHANGELOG.md b/CODSPEED-CHANGELOG.md index 6416e4bf7..61808930c 100644 --- a/CODSPEED-CHANGELOG.md +++ b/CODSPEED-CHANGELOG.md @@ -11,6 +11,16 @@ last-level cache when `--LL` (or its `--L2` alias) supplies the cache configurat The warning remains when LL is auto-detected. Cache geometry and simulation results are unchanged. +### arm64: decode reads of all EL0-visible ID registers + +Previously unsupported `MRS` reads in `S3_0_C0_C2_0` through `S3_0_C0_C7_7` +now return 0 instead of raising SIGILL, reporting the features as absent. +Linux emulates these reads natively. The decoder label for `ID_AA64PFR2_EL1` +was also corrected from `ID_AA64ZFR0_EL1`. + +`MRS` reads of `TPIDRRO_EL0` now return 0 instead of raising SIGILL, +matching Linux on AArch64. + ## Features ### Fixed Linux startup stack layout diff --git a/VEX/priv/guest_arm64_toIR.c b/VEX/priv/guest_arm64_toIR.c index ebab85b82..7c8566b45 100644 --- a/VEX/priv/guest_arm64_toIR.c +++ b/VEX/priv/guest_arm64_toIR.c @@ -7635,15 +7635,15 @@ Bool dis_ARM64_branch_etc(/*MB_OUT*/DisResult* dres, UInt insn, DIP("mrs %s, id_aa64pfr1_el1 (FAKED)\n", nameIReg32orZR(tt)); return True; } - /* ---- Case for ID_AA64ZFR0_EL1 (RO) ---- + /* ---- Case for ID_AA64PFR2_EL1 (RO) ---- We just return 0x0 here, as we don't support the opcodes of new commands in the emulation environment. - 0xD53804 010 Rt MRS rT, id_aa64zfr0_el1 + 0xD53804 010 Rt MRS rT, id_aa64pfr2_el1 */ if ((INSN(31,0) & 0xFFFFFFE0) == 0xD5380440 /*MRS*/) { UInt tt = INSN(4,0); putIReg64orZR(tt, mkU64(0x0)); - DIP("mrs %s, id_aa64zfr0_el1 (FAKED)\n", nameIReg64orZR(tt)); + DIP("mrs %s, id_aa64pfr2_el1 (FAKED)\n", nameIReg64orZR(tt)); return True; } /* ---- Case for ID_AA64DFR0_EL1 (RO) ---- @@ -7790,6 +7790,25 @@ Bool dis_ARM64_branch_etc(/*MB_OUT*/DisResult* dres, UInt insn, DIP("mrs %s, id_aa64mmfr2_el1 (FAKED)\n", nameIReg64orZR(tt)); return True; } + /* ---- Case for the remaining ID registers (RO) ---- + Linux emulates EL0 reads of Op0=3, Op1=0, CRn=0, CRm=2..7 and + returns 0 for every register it does not track, so a read never + traps natively. This covers ID_AA64ZFR0_EL1, ID_AA64SMFR0_EL1, + ID_AA64FPFR0_EL1, ID_AA64ISAR2_EL1, ID_AA64MMFR3_EL1, the AArch32 + ID registers and unallocated encodings. Return 0 for all of them: + it reports the features as absent, which matches what the cases + above report for ID_AA64PFR0_EL1 (no SVE) and ID_AA64PFR1_EL1 + (no SME). + 0xD538 0 CRm op2 Rt MRS rT, s3_0_c0_c_ + */ + if ((INSN(31,0) & 0xFFFFF000) == 0xD5380000 /*MRS*/ + && INSN(11,8) >= 2 && INSN(11,8) <= 7) { + UInt tt = INSN(4,0); + putIReg64orZR(tt, mkU64(0x0)); + DIP("mrs %s, s3_0_c0_c%u_%u (FAKED)\n", + nameIReg64orZR(tt), INSN(11,8), INSN(7,5)); + return True; + } /* ---- Cases for TPIDR_EL0 ---- 0xD51BD0 010 Rt MSR tpidr_el0, rT 0xD53BD0 010 Rt MRS rT, tpidr_el0 @@ -7807,6 +7826,18 @@ Bool dis_ARM64_branch_etc(/*MB_OUT*/DisResult* dres, UInt insn, } return True; } + /* ---- Case for TPIDRRO_EL0 (RO) ---- + EL0 can read but not write it. Linux zeroes it for AArch64 + tasks (it holds the TLS pointer only for AArch32 tasks), so + return 0. + 0xD53BD0 011 Rt MRS rT, tpidrro_el0 + */ + if ((INSN(31,0) & 0xFFFFFFE0) == 0xD53BD060 /*MRS*/) { + UInt tt = INSN(4,0); + putIReg64orZR(tt, mkU64(0x0)); + DIP("mrs %s, tpidrro_el0 (FAKED)\n", nameIReg64orZR(tt)); + return True; + } /* ---- Cases for FPCR ---- 0xD51B44 000 Rt MSR fpcr, rT 0xD53B44 000 Rt MSR rT, fpcr diff --git a/none/tests/arm64/Makefile.am b/none/tests/arm64/Makefile.am index 4b0d580c4..ff80dc7a2 100644 --- a/none/tests/arm64/Makefile.am +++ b/none/tests/arm64/Makefile.am @@ -17,6 +17,7 @@ EXTRA_DIST = \ integer.stdout.exp integer.stderr.exp integer.vgtest \ memory_test.stdout.exp memory_test.stderr.exp memory_test.vgtest \ memory_test.stdout.exp-clang \ + mrs_id_regs.stdout.exp mrs_id_regs.stderr.exp mrs_id_regs.vgtest \ atomics_v81.stdout.exp atomics_v81.stderr.exp atomics_v81.vgtest \ simd_v81.stdout.exp simd_v81.stderr.exp simd_v81.vgtest \ simd_dotprod.stdout.exp simd_dotprod.stderr.exp simd_dotprod.vgtest \ @@ -39,6 +40,7 @@ check_PROGRAMS = \ fp_and_simd \ integer \ memory_test \ + mrs_id_regs \ fmadd_sub \ ldxp_stxp diff --git a/none/tests/arm64/mrs_id_regs.c b/none/tests/arm64/mrs_id_regs.c new file mode 100644 index 000000000..81e6a60a9 --- /dev/null +++ b/none/tests/arm64/mrs_id_regs.c @@ -0,0 +1,32 @@ +/* Linux lets EL0 read the ID registers in Op0=3, Op1=0, CRn=0, CRm=2..7 + (by emulating the read) and TPIDRRO_EL0, so these reads must not raise + SIGILL under Valgrind. Valgrind reports the ID register features as + absent, and Linux zeroes TPIDRRO_EL0 for AArch64 tasks, so each read + returns 0. */ + +#include + +#define READ_ID_REG(name, sysreg) \ + do { \ + unsigned long value; \ + __asm__ volatile("mrs %0, " sysreg : "=r"(value)); \ + printf("%-17s 0x%016lx\n", name, value); \ + } while (0) + +int main(void) +{ + READ_ID_REG("ID_ISAR0_EL1", "S3_0_C0_C2_0"); + READ_ID_REG("MVFR0_EL1", "S3_0_C0_C3_0"); + READ_ID_REG("ID_AA64PFR2_EL1", "S3_0_C0_C4_2"); + READ_ID_REG("ID_AA64ZFR0_EL1", "S3_0_C0_C4_4"); + READ_ID_REG("ID_AA64SMFR0_EL1", "S3_0_C0_C4_5"); + READ_ID_REG("ID_AA64FPFR0_EL1", "S3_0_C0_C4_7"); + READ_ID_REG("ID_AA64DFR2_EL1", "S3_0_C0_C5_2"); + READ_ID_REG("ID_AA64ISAR2_EL1", "S3_0_C0_C6_2"); + READ_ID_REG("ID_AA64ISAR3_EL1", "S3_0_C0_C6_3"); + READ_ID_REG("ID_AA64MMFR3_EL1", "S3_0_C0_C7_3"); + READ_ID_REG("ID_AA64MMFR4_EL1", "S3_0_C0_C7_4"); + READ_ID_REG("S3_0_C0_C7_7", "S3_0_C0_C7_7"); + READ_ID_REG("TPIDRRO_EL0", "tpidrro_el0"); + return 0; +} diff --git a/none/tests/arm64/mrs_id_regs.stderr.exp b/none/tests/arm64/mrs_id_regs.stderr.exp new file mode 100644 index 000000000..e69de29bb diff --git a/none/tests/arm64/mrs_id_regs.stdout.exp b/none/tests/arm64/mrs_id_regs.stdout.exp new file mode 100644 index 000000000..10127ddf4 --- /dev/null +++ b/none/tests/arm64/mrs_id_regs.stdout.exp @@ -0,0 +1,13 @@ +ID_ISAR0_EL1 0x0000000000000000 +MVFR0_EL1 0x0000000000000000 +ID_AA64PFR2_EL1 0x0000000000000000 +ID_AA64ZFR0_EL1 0x0000000000000000 +ID_AA64SMFR0_EL1 0x0000000000000000 +ID_AA64FPFR0_EL1 0x0000000000000000 +ID_AA64DFR2_EL1 0x0000000000000000 +ID_AA64ISAR2_EL1 0x0000000000000000 +ID_AA64ISAR3_EL1 0x0000000000000000 +ID_AA64MMFR3_EL1 0x0000000000000000 +ID_AA64MMFR4_EL1 0x0000000000000000 +S3_0_C0_C7_7 0x0000000000000000 +TPIDRRO_EL0 0x0000000000000000 diff --git a/none/tests/arm64/mrs_id_regs.vgtest b/none/tests/arm64/mrs_id_regs.vgtest new file mode 100644 index 000000000..9cd53f30f --- /dev/null +++ b/none/tests/arm64/mrs_id_regs.vgtest @@ -0,0 +1,2 @@ +prog: mrs_id_regs +vgopts: -q