qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 4/4] tests/tcg/aarch64: Extend MTE gdbstub tests to system mode


From: Gustavo Romero
Subject: [PATCH 4/4] tests/tcg/aarch64: Extend MTE gdbstub tests to system mode
Date: Mon, 22 Jul 2024 16:07:09 +0000

Extend MTE gdbstub tests to also run in system mode (share tests
between user mode and system mode). The tests will only run if a version
of GDB that supports MTE is available in the test environment and if
available compiler supports the 'memtag' flag (-march=armv8.5-a+memtag).

For the tests running in system mode, a page that supports MTE
operations is necessary. Therefore, an MTE-enabled page is made
available (mapped) in the third 2 MB chunk of the second 1 GB space in
the flat mapping set in boot.S. A new binary is also introduced (mte.c)
for the test. It's linked against boot.S and run by QEMU in system mode.

Also, in boot.S bits ATA[43] and TCF[40] are set in SCTLR_EL1 to enable
access to allocation tags at EL1 and enable MTE_SYNC exceptions in case
of Tag Check Faults, and bit TBI0[37] is set in TCR_EL1 so the top byte
of the addresses are ignored in the translation and used for tagged
addresses.

Signed-off-by: Gustavo Romero <gustavo.romero@linaro.org>
---
 tests/tcg/aarch64/Makefile.softmmu-target | 36 +++++++++++++++++--
 tests/tcg/aarch64/Makefile.target         |  3 +-
 tests/tcg/aarch64/gdbstub/test-mte.py     | 44 +++++++++++++++--------
 tests/tcg/aarch64/system/boot.S           | 26 ++++++++++++--
 tests/tcg/aarch64/system/kernel.ld        |  5 +++
 tests/tcg/aarch64/system/mte.c            | 40 +++++++++++++++++++++
 6 files changed, 133 insertions(+), 21 deletions(-)
 create mode 100644 tests/tcg/aarch64/system/mte.c

diff --git a/tests/tcg/aarch64/Makefile.softmmu-target 
b/tests/tcg/aarch64/Makefile.softmmu-target
index dd6d595830..225a073e79 100644
--- a/tests/tcg/aarch64/Makefile.softmmu-target
+++ b/tests/tcg/aarch64/Makefile.softmmu-target
@@ -2,7 +2,9 @@
 # Aarch64 system tests
 #
 
-AARCH64_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/aarch64/system
+AARCH64_SRC=$(SRC_PATH)/tests/tcg/aarch64
+AARCH64_SYSTEM_SRC=$(AARCH64_SRC)/system
+
 VPATH+=$(AARCH64_SYSTEM_SRC)
 
 # These objects provide the basic boot code and helper functions for all tests
@@ -21,7 +23,8 @@ LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
 
 config-cc.mak: Makefile
        $(quiet-@)( \
-           $(call cc-option,-march=armv8.3-a, CROSS_CC_HAS_ARMV8_3)) 3> 
config-cc.mak
+           $(call cc-option,-march=armv8.3-a, CROSS_CC_HAS_ARMV8_3); \
+           $(call cc-option,-march=armv8.5-a+memtag, CROSS_CC_HAS_ARMV8_MTE)) 
3> config-cc.mak
 -include config-cc.mak
 
 # building head blobs
@@ -88,3 +91,32 @@ pauth-3:
 run-pauth-3:
        $(call skip-test, "RUN of pauth-3", "not built")
 endif
+
+ifneq ($(CROSS_CC_HAS_ARMV8_MTE),)
+QEMU_MTE_ENABLED_MACHINE=-M virt,mte=on -cpu max -display none
+QEMU_OPTS_WITH_MTE_ON = $(QEMU_MTE_ENABLED_MACHINE) $(QEMU_BASE_ARGS) -kernel
+mte: CFLAGS+=-march=armv8.5-a+memtag
+
+run-mte: QEMU_OPTS=$(QEMU_OPTS_WITH_MTE_ON)
+run-mte: mte
+
+ifeq ($(GDB_HAS_MTE),y)
+run-gdbstub-mte: QEMU_OPTS=$(QEMU_OPTS_WITH_MTE_ON)
+run-gdbstub-mte: mte
+       $(call run-test, $@, $(GDB_SCRIPT) \
+               --gdb $(GDB) \
+               --qemu $(QEMU) --qargs "-chardev 
file$(COMMA)path=$<.out$(COMMA)id=output $(QEMU_OPTS)" \
+               --bin $< --test $(AARCH64_SRC)/gdbstub/test-mte.py --test-args 
mode=\"system\", \
+       gdbstub MTE support)
+
+EXTRA_RUNS += run-gdbstub-mte
+else # !GDB_HAS_MTE
+run-gdbstub-mte:
+       $(call skip-test "RUN of gdbstub-mte", "GDB without MTE support")
+endif
+else # !CROSS_CC_HAS_ARMV8_MTE
+mte:
+       $(call skip-test, "BUILD of $@", "missing compiler support")
+run-mte:
+       $(call skip-test, "RUN of mte", "not build")
+endif
diff --git a/tests/tcg/aarch64/Makefile.target 
b/tests/tcg/aarch64/Makefile.target
index 8cc62eb456..2504517176 100644
--- a/tests/tcg/aarch64/Makefile.target
+++ b/tests/tcg/aarch64/Makefile.target
@@ -138,7 +138,8 @@ run-gdbstub-mte: mte-8
        $(call run-test, $@, $(GDB_SCRIPT) \
                --gdb $(GDB) \
                --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
-               --bin $< --test $(AARCH64_SRC)/gdbstub/test-mte.py, \
+               --bin $< --test $(AARCH64_SRC)/gdbstub/test-mte.py \
+               --test-args mode=\"user\", \
        gdbstub MTE support)
 
 EXTRA_RUNS += run-gdbstub-mte
diff --git a/tests/tcg/aarch64/gdbstub/test-mte.py 
b/tests/tcg/aarch64/gdbstub/test-mte.py
index 2db0663c1a..727999f277 100644
--- a/tests/tcg/aarch64/gdbstub/test-mte.py
+++ b/tests/tcg/aarch64/gdbstub/test-mte.py
@@ -1,13 +1,13 @@
 from __future__ import print_function
 #
 # Test GDB memory-tag commands that exercise the stubs for the 
qIsAddressTagged,
-# qMemTag, and QMemTag packets. Logical tag-only commands rely on local
-# operations, hence don't exercise any stub.
+# qMemTag, and QMemTag packets, which are used for manipulating allocation 
tags.
+# Logical tags-related commands rely on local operations, hence don't exercise
+# any stub and so are not used in this test.
 #
-# The test consists in breaking just after a atag() call (which sets the
-# allocation tag -- see mte-8.c for details) and setting/getting tags in
-# different memory locations and ranges starting at the address of the array
-# 'a'.
+# The test consists in breaking just after a tag is set in a specific memory
+# chunk, and then using the GDB 'memory-tagging' subcommands to set/get tags in
+# different memory locations and ranges in the MTE-enabled memory chunk.
 #
 # This is launched via tests/guest-debug/run-test.py
 #
@@ -23,12 +23,26 @@
 
 
 def run_test():
-    gdb.execute("break 95", False, True)
+    if mode == "system":
+        # Break address: where to break before performing the tests
+        # Addresss is the last insn. before 'main' returns. See mte.c
+        ba = "*main+52"
+        # Tagged address: the start of the MTE-enabled memory chunk to be 
tested
+        # Address is in the x0 register
+        ta = "$x0"
+    else: # mode="user"
+        # Line 95 in mte-8.c
+        ba = "95"
+        # 'a' is an array defined in C code. See mte-8.c
+        ta = "a"
+
+    gdb.execute(f"break {ba}", False, True)
     gdb.execute("continue", False, True)
+
     try:
         # Test if we can check correctly that the allocation tag for
         # array 'a' matches the logical tag after atag() is called.
-        co = gdb.execute("memory-tag check a", False, True)
+        co = gdb.execute(f"memory-tag check {ta}", False, True)
         tags_match = re.findall(PATTERN_0, co, re.MULTILINE)
         if tags_match:
             report(True, f"{tags_match[0]}")
@@ -40,19 +54,19 @@ def run_test():
 
         # Set the allocation tag for the first granule (16 bytes) of
         # address starting at 'a' address to a known value, i.e. 0x04.
-        gdb.execute("memory-tag set-allocation-tag a 1 04", False, True)
+        gdb.execute(f"memory-tag set-allocation-tag {ta} 1 04", False, True)
 
         # Then set the allocation tag for the second granule to a known
         # value, i.e. 0x06. This tests that contiguous tag granules are
         # set correct and don't run over each other.
-        gdb.execute("memory-tag set-allocation-tag a+16 1 06", False, True)
+        gdb.execute(f"memory-tag set-allocation-tag {ta}+16 1 06", False, True)
 
         # Read the known values back and check if they remain the same.
 
-        co = gdb.execute("memory-tag print-allocation-tag a", False, True)
+        co = gdb.execute(f"memory-tag print-allocation-tag {ta}", False, True)
         first_tag = re.match(PATTERN_1, co)[1]
 
-        co = gdb.execute("memory-tag print-allocation-tag a+16", False, True)
+        co = gdb.execute(f"memory-tag print-allocation-tag {ta}+16", False, 
True)
         second_tag = re.match(PATTERN_1, co)[1]
 
         if first_tag == "0x4" and second_tag == "0x6":
@@ -61,15 +75,15 @@ def run_test():
             report(False, "Can't set/print allocation tags!")
 
         # Now test fill pattern by setting a whole page with a pattern.
-        gdb.execute("memory-tag set-allocation-tag a 4096 0a0b", False, True)
+        gdb.execute(f"memory-tag set-allocation-tag {ta} 4096 0a0b", False, 
True)
 
         # And read back the tags of the last two granules in page so
         # we also test if the pattern is set correctly up to the end of
         # the page.
-        co = gdb.execute("memory-tag print-allocation-tag a+4096-32", False, 
True)
+        co = gdb.execute(f"memory-tag print-allocation-tag {ta}+4096-32", 
False, True)
         tag = re.match(PATTERN_1, co)[1]
 
-        co = gdb.execute("memory-tag print-allocation-tag a+4096-16", False, 
True)
+        co = gdb.execute(f"memory-tag print-allocation-tag {ta}+4096-16", 
False, True)
         last_tag = re.match(PATTERN_1, co)[1]
 
         if tag == "0xa" and last_tag == "0xb":
diff --git a/tests/tcg/aarch64/system/boot.S b/tests/tcg/aarch64/system/boot.S
index 501685d0ec..a12393d00b 100644
--- a/tests/tcg/aarch64/system/boot.S
+++ b/tests/tcg/aarch64/system/boot.S
@@ -135,11 +135,22 @@ __start:
        orr     x1, x1, x3
        str     x1, [x2]                        /* 2nd 2mb (.data & .bss)*/
 
+        /* Third block: .mte_page */
+       adrp    x1, .mte_page
+       add     x1, x1, :lo12:.mte_page
+       bic     x1, x1, #(1 << 21) - 1
+       and     x4, x1, x5
+       add     x2, x0, x4, lsr #(21 - 3)
+       ldr     x3, =(3 << 53) | 0x401 | 1 << 2 /* attr(AF, NX, block, 
AttrIndx=Attr1) */
+       orr     x1, x1, x3
+       str     x1, [x2]
+
        /* Setup/enable the MMU.  */
 
        /*
         * TCR_EL1 - Translation Control Registers
         *
+        * TBI0[37] = 0b1 => Top Byte ignored and used for tagged addresses
         * IPS[34:32] = 40-bit PA, 1TB
         * TG0[14:15] = b00 => 4kb granuale
         * ORGN0[11:10] = Outer: Normal, WB Read-Alloc No Write-Alloc Cacheable
@@ -152,16 +163,22 @@ __start:
         * with at least 1gb range to see RAM. So we start with a
         * level 1 lookup.
         */
-       ldr     x0, = (2 << 32) | 25 | (3 << 10) | (3 << 8)
+       ldr     x0, = (1 << 37) | (2 << 32) | 25 | (3 << 10) | (3 << 8)
        msr     tcr_el1, x0
 
-       mov     x0, #0xee                       /* Inner/outer cacheable WB */
+       /*
+        * Attr0: Normal, Inner/outer cacheable WB
+        * Attr1: Tagged Normal (MTE)
+        */
+       mov     x0, #0xf0ee
        msr     mair_el1, x0
        isb
 
        /*
         * SCTLR_EL1 - System Control Register
         *
+        * ATA[43] = 1 = enable access to allocation tags at EL1
+        * TCF[40] = 1 = Tag Check Faults cause a synchronous exception
         * WXN[19] = 0 = no effect, Write does not imply XN (execute never)
         * I[12] = Instruction cachability control
         * SA[3] = SP alignment check
@@ -169,7 +186,8 @@ __start:
         * M[0] = 1, enable stage 1 address translation for EL0/1
         */
        mrs     x0, sctlr_el1
-       ldr     x1, =0x100d                     /* bits I(12) SA(3) C(2) M(0) */
+       /* Bits set: ATA(43) TCF(40) I(12) SA(3) C(2) M(0) */
+       ldr     x1, =(0x100d | 1 << 43 | 1 << 40)
        bic     x0, x0, #(1 << 1)               /* clear bit A(1) */
        bic     x0, x0, #(1 << 19)              /* clear WXN */
        orr     x0, x0, x1                      /* set bits */
@@ -239,3 +257,5 @@ ttb_stage2:
 stack:
        .space 65536, 0
 stack_end:
+
+       .section .mte_page
diff --git a/tests/tcg/aarch64/system/kernel.ld 
b/tests/tcg/aarch64/system/kernel.ld
index 7b3a76dcbf..7c00c1c378 100644
--- a/tests/tcg/aarch64/system/kernel.ld
+++ b/tests/tcg/aarch64/system/kernel.ld
@@ -18,6 +18,11 @@ SECTIONS
     .bss : {
         *(.bss)
     }
+    /* align MTE section to next (third) 2mb */
+    . = ALIGN(1 << 22);
+    .mte : {
+        *(.mte_page)
+    }
     /DISCARD/ : {
         *(.ARM.attributes)
     }
diff --git a/tests/tcg/aarch64/system/mte.c b/tests/tcg/aarch64/system/mte.c
new file mode 100644
index 0000000000..58a5ac31ff
--- /dev/null
+++ b/tests/tcg/aarch64/system/mte.c
@@ -0,0 +1,40 @@
+#include <inttypes.h>
+
+int main(void)
+{
+    uint8_t *addr;
+
+    /*
+     * Third 2MB chunk in the second 1GB block.
+     * See .mte_page section in kernel.ld.
+     */
+    addr = (void *)((1UL << 30) | (1UL << 22));
+
+    asm (
+        /*
+         * Set GCR for randon tag generation. 0xA5 is just a random value to 
set
+         * GCR != 0 so the tag generated by 'irg' is not zero.
+         */
+        "ldr x1, =0xA5;"
+        "msr gcr_el1, x1;"
+
+         /* Generate a logical tag and put it in 'addr' pointer. */
+         "irg %[addr], %[addr];"
+
+         /*
+          * Store the generated tag to memory region pointed to by 'addr', i.e.
+          * set the allocation tag for the memory region.
+          */
+         "stg %[addr], [%[addr]];"
+
+         /*
+          * Store a random value (0xdeadbeef) to *addr. This must not cause any
+          * Tag Check Fault since logical and allocation tags are set the same.
+          */
+        "ldr x1, =0xdeadbeef;"
+        "str x1, [x0];"
+         : [addr] "+r" (addr)
+         :
+         :
+    );
+}
-- 
2.34.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]