Signed-off-by: Brian Cain <[email protected]>
---
 tests/tcg/hexagon/icinva.c        | 71 +++++++++++++++++++++++++++++++
 tests/tcg/hexagon/Makefile.target |  2 +
 2 files changed, 73 insertions(+)
 create mode 100644 tests/tcg/hexagon/icinva.c

diff --git a/tests/tcg/hexagon/icinva.c b/tests/tcg/hexagon/icinva.c
new file mode 100644
index 00000000000..0252e0f899d
--- /dev/null
+++ b/tests/tcg/hexagon/icinva.c
@@ -0,0 +1,71 @@
+/*
+ * Test that icinva ends the current translation block.
+ *
+ * icinva only invalidates the emulator's cached translation for a
+ * code range; it doesn't retroactively fix up code that has already
+ * been decoded as part of the still-executing translation block. If
+ * icinva doesn't force a new TB to start right after it, a packet
+ * patched via a store immediately before icinva (with no
+ * change-of-flow in between) still runs the stale decode baked into
+ * the current TB instead of the freshly-patched instruction.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+int err;
+
+#include "hex_test.h"
+
+/* Encoding of "r0 = #99" */
+#define ICINVA_NEW_INSN 0x7800cc60
+
+static uint32_t __attribute__((noinline)) test_icinva_smc(void)
+{
+    uint32_t result;
+
+    /*
+     * r1 = address of the "patch_slot" packet below (1:)
+     * Overwrite it with the "r0 = #99" encoding, invalidate the
+     * icache for that address, then fall straight through into it
+     * with no intervening jump/call.
+     */
+    asm volatile(
+        "r1 = ##1f\n"
+        "r2 = ##%[newinsn]\n"
+        "memw(r1) = r2\n"
+        "icinva(r1)\n"
+        "1:\n"
+        "   r0 = #11\n"
+        "%[out] = r0\n"
+        : [out] "=r"(result)
+        : [newinsn] "i"(ICINVA_NEW_INSN)
+        : "r0", "r1", "r2", "memory"
+    );
+
+    return result;
+}
+
+int main(void)
+{
+    long pagesize = sysconf(_SC_PAGESIZE);
+    uintptr_t page = (uintptr_t)test_icinva_smc & ~(pagesize - 1);
+    uint32_t result;
+
+    if (mprotect((void *)page, 2 * pagesize,
+                 PROT_READ | PROT_WRITE | PROT_EXEC) != 0) {
+        perror("mprotect");
+        return 1;
+    }
+
+    result = test_icinva_smc();
+    check32(result, 99);
+
+    puts(err ? "FAIL" : "PASS");
+    return err;
+}
diff --git a/tests/tcg/hexagon/Makefile.target 
b/tests/tcg/hexagon/Makefile.target
index 61adf6356e4..27268e66b7a 100644
--- a/tests/tcg/hexagon/Makefile.target
+++ b/tests/tcg/hexagon/Makefile.target
@@ -60,6 +60,7 @@ HEX_TESTS += invalid-encoding
 HEX_TESTS += multiple-writes
 HEX_TESTS += unaligned_pc
 HEX_TESTS += unaligned_data
+HEX_TESTS += icinva
 
 HEX_TESTS += test_abs
 HEX_TESTS += test_bitcnt
@@ -103,6 +104,7 @@ circ: circ.c hex_test.h
 dual_stores: dual_stores.c hex_test.h
 fpstuff: fpstuff.c hex_test.h
 hex_sigsegv: hex_sigsegv.c hex_test.h
+icinva: icinva.c hex_test.h
 load_align: load_align.c hex_test.h
 load_unpack: load_unpack.c hex_test.h
 mem_noshuf_exception: mem_noshuf_exception.c hex_test.h
-- 
2.34.1

Reply via email to