diff mbox series

[2/2] tests/tcg/s390x: Test modifying code using the MVC instruction

Message ID 20250128001338.11474-2-iii@linux.ibm.com (mailing list archive)
State New
Headers show
Series [1/2] target/s390x: Fix MVC not always invalidating translation blocks | expand

Commit Message

Ilya Leoshkevich Jan. 28, 2025, 12:12 a.m. UTC
Add a small test to prevent regressions.

Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
 tests/tcg/s390x/Makefile.softmmu-target |  1 +
 tests/tcg/s390x/mvc-smc.c               | 82 +++++++++++++++++++++++++
 2 files changed, 83 insertions(+)
 create mode 100644 tests/tcg/s390x/mvc-smc.c

Comments

Richard Henderson Jan. 28, 2025, 1:01 a.m. UTC | #1
On 1/27/25 16:12, Ilya Leoshkevich wrote:
> Add a small test to prevent regressions.
> 
> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
> ---
>   tests/tcg/s390x/Makefile.softmmu-target |  1 +
>   tests/tcg/s390x/mvc-smc.c               | 82 +++++++++++++++++++++++++
>   2 files changed, 83 insertions(+)
>   create mode 100644 tests/tcg/s390x/mvc-smc.c

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~

> 
> diff --git a/tests/tcg/s390x/Makefile.softmmu-target b/tests/tcg/s390x/Makefile.softmmu-target
> index 7adde2fa087..8cd4667c63b 100644
> --- a/tests/tcg/s390x/Makefile.softmmu-target
> +++ b/tests/tcg/s390x/Makefile.softmmu-target
> @@ -42,6 +42,7 @@ $(ASM_TESTS): LDFLAGS += -Wl,-T$(LINK_SCRIPT) -Wl,--build-id=none
>   $(ASM_TESTS): $(LINK_SCRIPT)
>   TESTS += $(ASM_TESTS)
>   
> +MULTIARCH_TESTS += mvc-smc
>   S390X_MULTIARCH_RUNTIME_OBJS = head64.o console.o $(MINILIB_OBJS)
>   $(MULTIARCH_TESTS): $(S390X_MULTIARCH_RUNTIME_OBJS)
>   $(MULTIARCH_TESTS): LDFLAGS += $(S390X_MULTIARCH_RUNTIME_OBJS)
> diff --git a/tests/tcg/s390x/mvc-smc.c b/tests/tcg/s390x/mvc-smc.c
> new file mode 100644
> index 00000000000..d68f60caa85
> --- /dev/null
> +++ b/tests/tcg/s390x/mvc-smc.c
> @@ -0,0 +1,82 @@
> +/*
> + * Test modifying code using the MVC instruction.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include <minilib.h>
> +
> +#define PAGE_SIZE 4096
> +#define BR_14_SIZE 2
> +#define RWX_OFFSET 2
> +
> +static unsigned char rw[PAGE_SIZE + BR_14_SIZE];
> +static unsigned char rwx[RWX_OFFSET + sizeof(rw)]
> +    __attribute__((aligned(PAGE_SIZE)));
> +
> +typedef unsigned long (*function_t)(unsigned long);
> +
> +static int emit_function(unsigned char *p, int n)
> +{
> +    int i = 0, val = 0;
> +
> +    while (i < n - 2) {
> +        /* aghi %r2,1 */
> +        p[i++] = 0xa7;
> +        p[i++] = 0x2b;
> +        p[i++] = 0x00;
> +        p[i++] = 0x01;
> +        val++;
> +    }
> +
> +    /* br %r14 */
> +    p[i++] = 0x07;
> +    p[i++] = 0xfe;
> +
> +    return val;
> +}
> +
> +static void memcpy_mvc(void *dest, void *src, unsigned long n)
> +{
> +    while (n >= 256) {
> +        asm("mvc 0(256,%[dest]),0(%[src])"
> +            :
> +            : [dest] "a" (dest)
> +            , [src] "a" (src)
> +            : "memory");
> +        dest += 256;
> +        src += 256;
> +        n -= 256;
> +    }
> +    asm("exrl %[n],0f\n"
> +        "j 1f\n"
> +        "0: mvc 0(1,%[dest]),0(%[src])\n"
> +        "1:"
> +        :
> +        : [dest] "a" (dest)
> +        , [src] "a" (src)
> +        , [n] "a" (n)
> +        : "memory");
> +}
> +
> +int main(void)
> +{
> +    int expected, size;
> +
> +    /* Create a TB. */
> +    size = sizeof(rwx) - RWX_OFFSET - 4;
> +    expected = emit_function(rwx + RWX_OFFSET, size);
> +    if (((function_t)(rwx + RWX_OFFSET))(0) != expected) {
> +        return 1;
> +    }
> +
> +    /* Overwrite the TB. */
> +    size += 4;
> +    expected = emit_function(rw, size);
> +    memcpy_mvc(rwx + RWX_OFFSET, rw, size);
> +    if (((function_t)(rwx + RWX_OFFSET))(0) != expected) {
> +        return 2;
> +    }
> +
> +    return 0;
> +}
diff mbox series

Patch

diff --git a/tests/tcg/s390x/Makefile.softmmu-target b/tests/tcg/s390x/Makefile.softmmu-target
index 7adde2fa087..8cd4667c63b 100644
--- a/tests/tcg/s390x/Makefile.softmmu-target
+++ b/tests/tcg/s390x/Makefile.softmmu-target
@@ -42,6 +42,7 @@  $(ASM_TESTS): LDFLAGS += -Wl,-T$(LINK_SCRIPT) -Wl,--build-id=none
 $(ASM_TESTS): $(LINK_SCRIPT)
 TESTS += $(ASM_TESTS)
 
+MULTIARCH_TESTS += mvc-smc
 S390X_MULTIARCH_RUNTIME_OBJS = head64.o console.o $(MINILIB_OBJS)
 $(MULTIARCH_TESTS): $(S390X_MULTIARCH_RUNTIME_OBJS)
 $(MULTIARCH_TESTS): LDFLAGS += $(S390X_MULTIARCH_RUNTIME_OBJS)
diff --git a/tests/tcg/s390x/mvc-smc.c b/tests/tcg/s390x/mvc-smc.c
new file mode 100644
index 00000000000..d68f60caa85
--- /dev/null
+++ b/tests/tcg/s390x/mvc-smc.c
@@ -0,0 +1,82 @@ 
+/*
+ * Test modifying code using the MVC instruction.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <minilib.h>
+
+#define PAGE_SIZE 4096
+#define BR_14_SIZE 2
+#define RWX_OFFSET 2
+
+static unsigned char rw[PAGE_SIZE + BR_14_SIZE];
+static unsigned char rwx[RWX_OFFSET + sizeof(rw)]
+    __attribute__((aligned(PAGE_SIZE)));
+
+typedef unsigned long (*function_t)(unsigned long);
+
+static int emit_function(unsigned char *p, int n)
+{
+    int i = 0, val = 0;
+
+    while (i < n - 2) {
+        /* aghi %r2,1 */
+        p[i++] = 0xa7;
+        p[i++] = 0x2b;
+        p[i++] = 0x00;
+        p[i++] = 0x01;
+        val++;
+    }
+
+    /* br %r14 */
+    p[i++] = 0x07;
+    p[i++] = 0xfe;
+
+    return val;
+}
+
+static void memcpy_mvc(void *dest, void *src, unsigned long n)
+{
+    while (n >= 256) {
+        asm("mvc 0(256,%[dest]),0(%[src])"
+            :
+            : [dest] "a" (dest)
+            , [src] "a" (src)
+            : "memory");
+        dest += 256;
+        src += 256;
+        n -= 256;
+    }
+    asm("exrl %[n],0f\n"
+        "j 1f\n"
+        "0: mvc 0(1,%[dest]),0(%[src])\n"
+        "1:"
+        :
+        : [dest] "a" (dest)
+        , [src] "a" (src)
+        , [n] "a" (n)
+        : "memory");
+}
+
+int main(void)
+{
+    int expected, size;
+
+    /* Create a TB. */
+    size = sizeof(rwx) - RWX_OFFSET - 4;
+    expected = emit_function(rwx + RWX_OFFSET, size);
+    if (((function_t)(rwx + RWX_OFFSET))(0) != expected) {
+        return 1;
+    }
+
+    /* Overwrite the TB. */
+    size += 4;
+    expected = emit_function(rw, size);
+    memcpy_mvc(rwx + RWX_OFFSET, rw, size);
+    if (((function_t)(rwx + RWX_OFFSET))(0) != expected) {
+        return 2;
+    }
+
+    return 0;
+}