From: Brian Cain <[email protected]>

Add check_rev_gating, a linux-user test that verifies the decoder
rejects instructions from a newer CPU revision than the one selected
by the ELF binary's e_flags.

Co-authored-by: Taylor Simpson <[email protected]>
Co-authored-by: Matheus Tavares Bernardino <[email protected]>
Signed-off-by: Brian Cain <[email protected]>
---
 tests/tcg/hexagon/check_rev_gating.c | 141 +++++++++++++++++++++++++++
 tests/tcg/hexagon/Makefile.target    |   6 ++
 2 files changed, 147 insertions(+)
 create mode 100644 tests/tcg/hexagon/check_rev_gating.c

diff --git a/tests/tcg/hexagon/check_rev_gating.c 
b/tests/tcg/hexagon/check_rev_gating.c
new file mode 100644
index 0000000000..26b66f5455
--- /dev/null
+++ b/tests/tcg/hexagon/check_rev_gating.c
@@ -0,0 +1,141 @@
+/*
+ * Test that instructions from a newer revision than the running CPU
+ * are rejected with SIGILL.
+ *
+ * Compiled with -mv66 so that e_flags selects CPU v66. The test embeds
+ * a v68 instruction (L2_loadw_aq: "r0 = memw_aq(r0)") via .word
+ * encoding. The revision-gated decoder must reject it, and linux-user
+ * must deliver SIGILL.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <assert.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void *resume_pc;
+static int signals_handled;
+static int expected_signals;
+
+static void handle_sigill(int sig, siginfo_t *info, void *puc)
+{
+    ucontext_t *uc = (ucontext_t *)puc;
+
+    if (sig != SIGILL) {
+        _exit(EXIT_FAILURE);
+    }
+
+    uc->uc_mcontext.r0 = SIGILL;
+    uc->uc_mcontext.pc = (unsigned long)resume_pc;
+    signals_handled++;
+}
+
+/*
+ * Try to execute an instruction introduced after v66
+ * On a v66 CPU this must raise SIGILL.
+ *
+ * Since we are building for v66, the assembler will reject
+ * the instructions, so introduce them with .word.
+ */
+#define TRY_FUNC(NAME, WORD) \
+static int try_##NAME(void) \
+{ \
+    int sig; \
+    expected_signals++; \
+    asm volatile( \
+        "r0 = #0\n" \
+        "r1 = ##1f\n" \
+        "memw(%1) = r1\n" \
+        WORD \
+        "1:\n" \
+        "%0 = r0\n" \
+        : "=r"(sig) \
+        : "r"(&resume_pc) \
+        : "r0", "r1", "memory"); \
+    return sig; \
+}
+
+TRY_FUNC(v68_loadw_aq,
+         ".word 0x9200c800    /* { r0 = memw_aq(r0) } */\n")
+TRY_FUNC(v68_loadd_aq,
+         ".word 0x9201d800    /* r1:0 = memd_aq(r1) */\n")
+TRY_FUNC(v68_release_at,
+         ".word 0xa0e0c00c    /* release(r0):at */\n")
+TRY_FUNC(v68_release_st,
+         ".word 0xa0e0c02c    /* release(r0):st */\n")
+TRY_FUNC(v68_storew_rl_at,
+         ".word 0xa0a0c108    /* memw_rl(r0):at = r1 */\n")
+TRY_FUNC(v68_stored_rl_at,
+         ".word 0xa0e2c008    /* memd_rl(r2):at = r1:0 */\n")
+TRY_FUNC(v68_storew_rl_st,
+         ".word 0xa0a0c128    /* memw_rl(r0):st = r1 */\n")
+TRY_FUNC(v68_stored_rl_st,
+         ".word 0xa0e2c028    /* memd_rl(r2):st = r1:0 */\n")
+
+TRY_FUNC(v68hvx_v6mpy,
+         ".word 0x1f42e424    /* v5:4.w = v6mpy(v5:4.ub, v3:2.b, #1):v */\n")
+
+TRY_FUNC(v69hvx_vasrvuhubrndsat,
+         ".word 0x1d06c465    /* v5.ub = vasr(v5:4.uh, v6.ub):rnd:sat */\n")
+TRY_FUNC(v69hvx_vasrvuhubsat,
+         ".word 0x1d06c445    /* v5.ub = vasr(v5:4.uh, v6.ub):sat */\n")
+TRY_FUNC(v69hvx_vasrvwuhrndsat,
+         ".word 0x1d06c425    /* v5.uh = vasr(v5:4.w, v6.uh):rnd:sat */\n")
+TRY_FUNC(v69hvx_vasrvwuhsat,
+         ".word 0x1d06c405    /* v5.uh = vasr(v5:4.w, v6.uh):sat */\n")
+TRY_FUNC(v69hvx_vassign_tmp,
+         ".word 0x1e014dcc    /* { v12.tmp = v13 */\n"
+         ".word 0x1c43cc04    /*    v4.w = vadd(v12.w, v3.w) } */\n")
+TRY_FUNC(v69hvx_vcombine_tmp,
+         ".word 0x1eae4fec    /* { v13:12.tmp = vcombine(v15, v14) */\n"
+         ".word 0x1c434c04    /*   v4.w = vadd(v12.w, v3.w) */\n"
+         ".word 0x1e03edf0    /*   v16 = v13 } */\n")
+TRY_FUNC(v69hvx_vmpyuhvs,
+         ".word 0x1fc5e4e4    /* v4.uh = vmpy(V4.uh, v5.uh):>>16 */\n")
+
+TRY_FUNC(v73_callrh,
+         ".word 0x50c5c000    /* callrh r5 */\n")
+TRY_FUNC(v73_jumprh,
+         ".word 0x52c0c000    /* jumprh r0 */\n")
+
+int main(void)
+{
+    struct sigaction act;
+
+    memset(&act, 0, sizeof(act));
+    act.sa_sigaction = handle_sigill;
+    act.sa_flags = SA_SIGINFO;
+    assert(sigaction(SIGILL, &act, NULL) == 0);
+
+    assert(try_v68_loadw_aq() == SIGILL);
+    assert(try_v68_loadd_aq() == SIGILL);
+    assert(try_v68_release_at() == SIGILL);
+    assert(try_v68_release_st() == SIGILL);
+    assert(try_v68_storew_rl_at() == SIGILL);
+    assert(try_v68_stored_rl_at() == SIGILL);
+    assert(try_v68_storew_rl_st() == SIGILL);
+    assert(try_v68_stored_rl_st() == SIGILL);
+
+    assert(try_v68hvx_v6mpy() == SIGILL);
+
+    assert(try_v69hvx_vasrvuhubrndsat() == SIGILL);
+    assert(try_v69hvx_vasrvuhubsat() == SIGILL);
+    assert(try_v69hvx_vasrvwuhrndsat() == SIGILL);
+    assert(try_v69hvx_vasrvwuhsat() == SIGILL);
+    assert(try_v69hvx_vassign_tmp() == SIGILL);
+    assert(try_v69hvx_vcombine_tmp() == SIGILL);
+    assert(try_v69hvx_vmpyuhvs() == SIGILL);
+
+    assert(try_v73_callrh() == SIGILL);
+    assert(try_v73_jumprh() == SIGILL);
+
+    assert(signals_handled == expected_signals);
+
+    puts("PASS");
+    return EXIT_SUCCESS;
+}
diff --git a/tests/tcg/hexagon/Makefile.target 
b/tests/tcg/hexagon/Makefile.target
index f86f02bb31..0050370806 100644
--- a/tests/tcg/hexagon/Makefile.target
+++ b/tests/tcg/hexagon/Makefile.target
@@ -81,6 +81,7 @@ HEX_TESTS += test_vminh
 HEX_TESTS += test_vpmpyh
 HEX_TESTS += test_vspliceb
 
+HEX_TESTS += check_rev_gating
 HEX_TESTS += v68_scalar
 HEX_TESTS += v68_hvx
 HEX_TESTS += v69_hvx
@@ -106,6 +107,11 @@ read_write_overlap: read_write_overlap.c hex_test.h
 reg_mut: reg_mut.c hex_test.h
 unaligned_pc: unaligned_pc.c
 
+# Compile for v66 so that the ELF selects a v66 CPU; the test then
+# exercises revision gating by executing a v68 .word instruction.
+check_rev_gating: check_rev_gating.c
+       $(CC) $(CFLAGS) -mv66 -O2 $< -o $@ $(LDFLAGS)
+
 # This test has to be compiled for the -mv67t target
 usr: usr.c hex_test.h
        $(CC) $(CFLAGS) -mv67t -O2 -Wno-inline-asm -Wno-expansion-to-defined $< 
-o $@ $(LDFLAGS)
-- 
2.43.0


Reply via email to