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