* [PATCH 1/7] tests/tcg: introduce a lib dir for aarch64 system tests
2026-04-17 16:43 [PATCH 0/7] tests/tcg: more capabilities for aarch64-softmmu tests Alex Bennée
@ 2026-04-17 16:43 ` Alex Bennée
2026-04-24 1:38 ` Richard Henderson
2026-04-17 16:43 ` [PATCH 2/7] tests/tcg: convert aarch64 feat-xs test to use helpers Alex Bennée
` (5 subsequent siblings)
6 siblings, 1 reply; 13+ messages in thread
From: Alex Bennée @ 2026-04-17 16:43 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-arm, Peter Maydell, Alex Bennée
We are about to add some more helpers but lets start by adding a
simple wrapper for reading and writing system registers.
Do note the subtle switch of ordering for write_sysreg() which matches
the change the kernel made sometime in 2021 (see 272a067df in linux.git).
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
tests/tcg/aarch64/system/lib/sysregs.h | 22 ++++++++++++++++++++++
tests/tcg/aarch64/system/vtimer.c | 23 ++++-------------------
tests/tcg/aarch64/Makefile.softmmu-target | 3 ++-
3 files changed, 28 insertions(+), 20 deletions(-)
create mode 100644 tests/tcg/aarch64/system/lib/sysregs.h
diff --git a/tests/tcg/aarch64/system/lib/sysregs.h b/tests/tcg/aarch64/system/lib/sysregs.h
new file mode 100644
index 00000000000..b1c465e0746
--- /dev/null
+++ b/tests/tcg/aarch64/system/lib/sysregs.h
@@ -0,0 +1,22 @@
+/*
+ * AArch64 system register helpers
+ *
+ * Based on the helpers from Linux
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#define __stringify_1(x...) #x
+#define __stringify(x...) __stringify_1(x)
+
+#define read_sysreg(r) ({ \
+ uint64_t __val; \
+ asm volatile("mrs %0, " __stringify(r) : "=r" (__val)); \
+ __val; \
+})
+
+#define write_sysreg(v, r) do { \
+ uint64_t __val = (uint64_t)(v); \
+ asm volatile("msr " __stringify(r) ", %x0" \
+ : : "rZ" (__val)); \
+} while (0)
diff --git a/tests/tcg/aarch64/system/vtimer.c b/tests/tcg/aarch64/system/vtimer.c
index 7d725eced34..b6bde49ce30 100644
--- a/tests/tcg/aarch64/system/vtimer.c
+++ b/tests/tcg/aarch64/system/vtimer.c
@@ -8,22 +8,7 @@
#include <stdint.h>
#include <minilib.h>
-
-/* grabbed from Linux */
-#define __stringify_1(x...) #x
-#define __stringify(x...) __stringify_1(x)
-
-#define read_sysreg(r) ({ \
- uint64_t __val; \
- asm volatile("mrs %0, " __stringify(r) : "=r" (__val)); \
- __val; \
-})
-
-#define write_sysreg(r, v) do { \
- uint64_t __val = (uint64_t)(v); \
- asm volatile("msr " __stringify(r) ", %x0" \
- : : "rZ" (__val)); \
-} while (0)
+#include "sysregs.h"
int main(void)
{
@@ -31,9 +16,9 @@ int main(void)
ml_printf("VTimer Test\n");
- write_sysreg(cntvoff_el2, 1);
- write_sysreg(cntv_cval_el0, -1);
- write_sysreg(cntv_ctl_el0, 1);
+ write_sysreg(1, cntvoff_el2);
+ write_sysreg(-1, cntv_cval_el0);
+ write_sysreg(1, cntv_ctl_el0);
ml_printf("cntvoff_el2=%lx\n", read_sysreg(cntvoff_el2));
ml_printf("cntv_cval_el0=%lx\n", read_sysreg(cntv_cval_el0));
diff --git a/tests/tcg/aarch64/Makefile.softmmu-target b/tests/tcg/aarch64/Makefile.softmmu-target
index f7a7d2b800f..c7f44803c73 100644
--- a/tests/tcg/aarch64/Makefile.softmmu-target
+++ b/tests/tcg/aarch64/Makefile.softmmu-target
@@ -4,6 +4,7 @@
AARCH64_SRC=$(SRC_PATH)/tests/tcg/aarch64
AARCH64_SYSTEM_SRC=$(AARCH64_SRC)/system
+AARCH64_SYSTEM_LIB=$(AARCH64_SRC)/system/lib
VPATH+=$(AARCH64_SYSTEM_SRC)
@@ -24,7 +25,7 @@ LINK_SCRIPT=$(AARCH64_SYSTEM_SRC)/kernel.ld
LDFLAGS=-Wl,-T$(LINK_SCRIPT)
TESTS+=$(AARCH64_TESTS) $(MULTIARCH_TESTS)
EXTRA_RUNS+=$(MULTIARCH_RUNS)
-CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC)
+CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC) -I $(AARCH64_SYSTEM_LIB)
LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
config-cc.mak: Makefile
--
2.47.3
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH 1/7] tests/tcg: introduce a lib dir for aarch64 system tests
2026-04-17 16:43 ` [PATCH 1/7] tests/tcg: introduce a lib dir for aarch64 system tests Alex Bennée
@ 2026-04-24 1:38 ` Richard Henderson
0 siblings, 0 replies; 13+ messages in thread
From: Richard Henderson @ 2026-04-24 1:38 UTC (permalink / raw)
To: qemu-devel
On 4/18/26 02:43, Alex Bennée wrote:
> We are about to add some more helpers but lets start by adding a
> simple wrapper for reading and writing system registers.
>
> Do note the subtle switch of ordering for write_sysreg() which matches
> the change the kernel made sometime in 2021 (see 272a067df in linux.git).
>
> Signed-off-by: Alex Bennée<alex.bennee@linaro.org>
> ---
> tests/tcg/aarch64/system/lib/sysregs.h | 22 ++++++++++++++++++++++
> tests/tcg/aarch64/system/vtimer.c | 23 ++++-------------------
> tests/tcg/aarch64/Makefile.softmmu-target | 3 ++-
> 3 files changed, 28 insertions(+), 20 deletions(-)
> create mode 100644 tests/tcg/aarch64/system/lib/sysregs.h
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 2/7] tests/tcg: convert aarch64 feat-xs test to use helpers
2026-04-17 16:43 [PATCH 0/7] tests/tcg: more capabilities for aarch64-softmmu tests Alex Bennée
2026-04-17 16:43 ` [PATCH 1/7] tests/tcg: introduce a lib dir for aarch64 system tests Alex Bennée
@ 2026-04-17 16:43 ` Alex Bennée
2026-04-24 1:38 ` Richard Henderson
2026-04-17 16:43 ` [PATCH 3/7] tests/tcg: convert aarch64 asid2 test to use sysreg helpers Alex Bennée
` (4 subsequent siblings)
6 siblings, 1 reply; 13+ messages in thread
From: Alex Bennée @ 2026-04-17 16:43 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-arm, Peter Maydell, Alex Bennée
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
tests/tcg/aarch64/system/feat-xs.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tests/tcg/aarch64/system/feat-xs.c b/tests/tcg/aarch64/system/feat-xs.c
index f310fc837e0..e2324cef1af 100644
--- a/tests/tcg/aarch64/system/feat-xs.c
+++ b/tests/tcg/aarch64/system/feat-xs.c
@@ -8,12 +8,12 @@
#include <minilib.h>
#include <stdint.h>
+#include "sysregs.h"
int main(void)
{
- uint64_t isar1;
+ uint64_t isar1 = read_sysreg(id_aa64isar1_el1);
- asm volatile ("mrs %0, id_aa64isar1_el1" : "=r"(isar1));
if (((isar1 >> 56) & 0xf) < 1) {
ml_printf("FEAT_XS not supported by CPU");
return 1;
--
2.47.3
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH 2/7] tests/tcg: convert aarch64 feat-xs test to use helpers
2026-04-17 16:43 ` [PATCH 2/7] tests/tcg: convert aarch64 feat-xs test to use helpers Alex Bennée
@ 2026-04-24 1:38 ` Richard Henderson
0 siblings, 0 replies; 13+ messages in thread
From: Richard Henderson @ 2026-04-24 1:38 UTC (permalink / raw)
To: qemu-devel
On 4/18/26 02:43, Alex Bennée wrote:
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
> tests/tcg/aarch64/system/feat-xs.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/tests/tcg/aarch64/system/feat-xs.c b/tests/tcg/aarch64/system/feat-xs.c
> index f310fc837e0..e2324cef1af 100644
> --- a/tests/tcg/aarch64/system/feat-xs.c
> +++ b/tests/tcg/aarch64/system/feat-xs.c
> @@ -8,12 +8,12 @@
>
> #include <minilib.h>
> #include <stdint.h>
> +#include "sysregs.h"
>
> int main(void)
> {
> - uint64_t isar1;
> + uint64_t isar1 = read_sysreg(id_aa64isar1_el1);
>
> - asm volatile ("mrs %0, id_aa64isar1_el1" : "=r"(isar1));
> if (((isar1 >> 56) & 0xf) < 1) {
> ml_printf("FEAT_XS not supported by CPU");
> return 1;
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 3/7] tests/tcg: convert aarch64 asid2 test to use sysreg helpers
2026-04-17 16:43 [PATCH 0/7] tests/tcg: more capabilities for aarch64-softmmu tests Alex Bennée
2026-04-17 16:43 ` [PATCH 1/7] tests/tcg: introduce a lib dir for aarch64 system tests Alex Bennée
2026-04-17 16:43 ` [PATCH 2/7] tests/tcg: convert aarch64 feat-xs test to use helpers Alex Bennée
@ 2026-04-17 16:43 ` Alex Bennée
2026-04-24 1:39 ` Richard Henderson
2026-04-17 16:43 ` [PATCH 4/7] tests/tcg: move aarch64 page table setup to c code Alex Bennée
` (3 subsequent siblings)
6 siblings, 1 reply; 13+ messages in thread
From: Alex Bennée @ 2026-04-17 16:43 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-arm, Peter Maydell, Alex Bennée
While we are at it we can reduce the number of temporary variables
needed and fix a format string error.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
tests/tcg/aarch64/system/asid2.c | 35 ++++++++++++++------------------
1 file changed, 15 insertions(+), 20 deletions(-)
diff --git a/tests/tcg/aarch64/system/asid2.c b/tests/tcg/aarch64/system/asid2.c
index 7d5466af34a..8c93024b858 100644
--- a/tests/tcg/aarch64/system/asid2.c
+++ b/tests/tcg/aarch64/system/asid2.c
@@ -9,10 +9,11 @@
#include <stdint.h>
#include <minilib.h>
+#include "sysregs.h"
-#define ID_AA64MMFR3_EL1 "S3_0_C0_C7_3"
-#define ID_AA64MMFR4_EL1 "S3_0_C0_C7_4"
-#define TCR2_EL1 "S3_0_C2_C0_3"
+#define ID_AA64MMFR3_EL1 S3_0_C0_C7_3
+#define ID_AA64MMFR4_EL1 S3_0_C0_C7_4
+#define TCR2_EL1 S3_0_C2_C0_3
int main()
{
@@ -23,7 +24,7 @@ int main()
* not enabled and read as the written value if A2 is enabled.
*/
- uint64_t out;
+ uint64_t read_tcr2;
uint64_t idreg3;
uint64_t idreg4;
int tcr2_present;
@@ -31,11 +32,8 @@ int main()
/* Mask is FNG1, FNG0, and A2 */
const uint64_t feature_mask = (1ULL << 18 | 1ULL << 17 | 1ULL << 16);
- const uint64_t in = feature_mask;
-
- asm("mrs %[idreg3], " ID_AA64MMFR3_EL1 "\n\t"
- : [idreg3] "=r" (idreg3));
+ idreg3 = read_sysreg(ID_AA64MMFR3_EL1);
tcr2_present = ((idreg3 & 0xF) != 0);
if (!tcr2_present) {
@@ -43,33 +41,30 @@ int main()
return 0;
}
- asm("mrs %[idreg4], " ID_AA64MMFR4_EL1 "\n\t"
- : [idreg4] "=r" (idreg4));
-
+ idreg4 = read_sysreg(ID_AA64MMFR4_EL1);
asid2_present = ((idreg4 & 0xF00) != 0);
- asm("msr " TCR2_EL1 ", %[x0]\n\t"
- "mrs %[x1], " TCR2_EL1 "\n\t"
- : [x1] "=r" (out)
- : [x0] "r" (in));
+ /* write the feature mask and read back */
+ write_sysreg(feature_mask, TCR2_EL1);
+ read_tcr2 = read_sysreg(TCR2_EL1);
if (asid2_present) {
- if ((out & feature_mask) == in) {
+ if ((read_tcr2 & feature_mask) == feature_mask) {
ml_printf("OK\n");
return 0;
} else {
ml_printf("FAIL: ASID2 present, but read value %lx != "
"written value %lx\n",
- out & feature_mask, in);
+ read_tcr2 & feature_mask, feature_mask);
return 1;
}
} else {
- if (out == 0) {
+ if (read_tcr2 == 0) {
ml_printf("TCR2_EL1 reads as RES0 as expected\n");
return 0;
} else {
- ml_printf("FAIL: ASID2, missing but read value %lx != 0\n",
- out & feature_mask, in);
+ ml_printf("FAIL: ASID2, missing but read value %lx != %lx\n",
+ read_tcr2 & feature_mask, feature_mask);
return 1;
}
}
--
2.47.3
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 4/7] tests/tcg: move aarch64 page table setup to c code
2026-04-17 16:43 [PATCH 0/7] tests/tcg: more capabilities for aarch64-softmmu tests Alex Bennée
` (2 preceding siblings ...)
2026-04-17 16:43 ` [PATCH 3/7] tests/tcg: convert aarch64 asid2 test to use sysreg helpers Alex Bennée
@ 2026-04-17 16:43 ` Alex Bennée
2026-05-07 17:13 ` Jim MacArthur
2026-04-17 16:43 ` [PATCH 5/7] tests/tcg: add HW page for aarch64 tests Alex Bennée
` (2 subsequent siblings)
6 siblings, 1 reply; 13+ messages in thread
From: Alex Bennée @ 2026-04-17 16:43 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-arm, Peter Maydell, Alex Bennée
If we want more flexibility messing around with page tables lets do it
without having to rely on assembly for it.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
AJB
- a result of -O0 does mean each helper ends up with a stack frame
being needed to do the relatively simple mask and shift. I've
experimented with -O1 and trying to manually enable inlining but
couldn't get anything to work.
---
tests/tcg/aarch64/system/lib/pgtable.h | 80 ++++++++++++++++
tests/tcg/aarch64/system/lib/sysregs.h | 20 ++++
tests/tcg/aarch64/system/lib/pgtable.c | 60 ++++++++++++
tests/tcg/aarch64/Makefile.softmmu-target | 9 +-
tests/tcg/aarch64/system/boot.S | 109 +---------------------
tests/tcg/aarch64/system/kernel.ld | 3 +
6 files changed, 170 insertions(+), 111 deletions(-)
create mode 100644 tests/tcg/aarch64/system/lib/pgtable.h
create mode 100644 tests/tcg/aarch64/system/lib/pgtable.c
diff --git a/tests/tcg/aarch64/system/lib/pgtable.h b/tests/tcg/aarch64/system/lib/pgtable.h
new file mode 100644
index 00000000000..c5048c3eea1
--- /dev/null
+++ b/tests/tcg/aarch64/system/lib/pgtable.h
@@ -0,0 +1,80 @@
+/*
+ * AArch64 page table helpers
+ *
+ * Some simple helper functions for setting the page table entries.
+ *
+ * Copyright (C) 2026 Linaro Ltd.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+/*
+ * Page Table Descriptors
+ */
+#define DESC_VALID (1ULL << 0)
+#define DESC_TYPE_TABLE (1ULL << 1)
+#define DESC_TYPE_BLOCK (0ULL << 1)
+#define DESC_TYPE_PAGE (1ULL << 1)
+
+#define DESC_AF (1ULL << 10)
+#define DESC_ATTRINDX(i) ((uint64_t)(i) << 2)
+#define DESC_NS (1ULL << 5)
+#define DESC_UXN (1ULL << 53)
+#define DESC_PXN (1ULL << 54)
+
+#define DESC_ADDR_MASK 0x0000FFFFFFFFF000ULL
+#define DESC_ADDR_BLOCK_L1 0x0000FFFFC0000000ULL
+#define DESC_ADDR_BLOCK_L2 0x0000FFFFFFE00000ULL
+
+/* Stage 2 specific */
+#define DESC_S2_AP_RW (3ULL << 6)
+#define DESC_S2_MEMATTR_NORMAL (0xfULL << 2)
+
+/**
+ * pgt_map_l1_table - Setup a Level 1 table pointing to a Level 2 table
+ * @table: the level 1 table
+ * @va: the virtual address to map
+ * @next_table: the level 2 table to point to
+ */
+static inline void pgt_map_l1_table(uint64_t *table, uintptr_t va, uint64_t *next_table)
+{
+ int index = (va >> 30) & 0x1ff;
+ table[index] = ((uintptr_t)next_table & DESC_ADDR_MASK) | DESC_TYPE_TABLE | DESC_VALID;
+}
+
+/**
+ * pgt_map_l1_block - Setup a Level 1 block mapping (1GB)
+ * @table: the level 1 table
+ * @va: the virtual address to map
+ * @pa: the physical address to map to
+ * @flags: the descriptor flags (e.g. DESC_AF | ...)
+ */
+static inline void pgt_map_l1_block(uint64_t *table, uintptr_t va, uintptr_t pa, uint64_t flags)
+{
+ int index = (va >> 30) & 0x1ff;
+ table[index] = (pa & DESC_ADDR_BLOCK_L1) | flags | DESC_TYPE_BLOCK | DESC_VALID;
+}
+
+/**
+ * pgt_map_l2_block - Setup a Level 2 block mapping (2MB)
+ * @table: the level 2 table
+ * @va: the virtual address to map
+ * @pa: the physical address to map to
+ * @flags: the descriptor flags (e.g. DESC_AF | ...)
+ */
+static inline void pgt_map_l2_block(uint64_t *table, uintptr_t va, uintptr_t pa, uint64_t flags)
+{
+ int index = (va >> 21) & 0x1ff;
+ table[index] = (pa & DESC_ADDR_BLOCK_L2) | flags | DESC_TYPE_BLOCK | DESC_VALID;
+}
+
+/**
+ * flat_map_stage2 - Setup a flat (VA==PA) stage 2 mapping
+ * @table: the level 2 table
+ * @addr: the VA/PA to map
+ * @flags: the descriptor flags (e.g. DESC_AF | ...)
+ */
+static inline void flat_map_stage2(uint64_t *table, uintptr_t addr, uint64_t flags)
+{
+ pgt_map_l2_block(table, addr, addr, flags);
+}
diff --git a/tests/tcg/aarch64/system/lib/sysregs.h b/tests/tcg/aarch64/system/lib/sysregs.h
index b1c465e0746..6e714f46842 100644
--- a/tests/tcg/aarch64/system/lib/sysregs.h
+++ b/tests/tcg/aarch64/system/lib/sysregs.h
@@ -20,3 +20,23 @@
asm volatile("msr " __stringify(r) ", %x0" \
: : "rZ" (__val)); \
} while (0)
+
+#define isb() asm volatile("isb" : : : "memory")
+#define dsb(opt) asm volatile("dsb " #opt : : : "memory")
+
+/*
+ * SCTLR_EL1 Bits
+ */
+#define SCTLR_EL1_M (1ULL << 0) /* enable MMU for EL0/1 */
+#define SCTLR_EL1_C (1ULL << 2) /* Data cachability control */
+#define SCTLR_EL1_SA (1ULL << 3) /* SP alignment check */
+#define SCTLR_EL1_I (1ULL << 12) /* Instruction cachability control */
+
+/*
+ * TCR_EL1 Bits
+ */
+#define TCR_EL1_T0SZ(s) ((s) & 0x3fULL)
+#define TCR_EL1_IRGN0_WBWA (3ULL << 8)
+#define TCR_EL1_ORGN0_WBWA (3ULL << 10)
+#define TCR_EL1_IPS_40BIT (2ULL << 32)
+#define TCR_EL1_TG0_4KB (0ULL << 14)
diff --git a/tests/tcg/aarch64/system/lib/pgtable.c b/tests/tcg/aarch64/system/lib/pgtable.c
new file mode 100644
index 00000000000..a558f5f0dd5
--- /dev/null
+++ b/tests/tcg/aarch64/system/lib/pgtable.c
@@ -0,0 +1,60 @@
+#include <stdint.h>
+#include "sysregs.h"
+#include "pgtable.h"
+
+/*
+ * Page table setup for AArch64 system tests.
+ * We use a flat identity mapping.
+ */
+
+/* Symbols defined in kernel.ld */
+extern char _text_start[];
+extern char _data_start[];
+extern char _tag_start[];
+
+/* Assume these start zeroed */
+uint64_t ttb_l1[512] __attribute__((aligned(4096)));
+uint64_t ttb_l2[512] __attribute__((aligned(4096)));
+
+/*
+ * Setup a flat address mapping page-tables. Stage one simply
+ * maps RAM to the first Gb. The stage2 tables have two 2mb
+ * translation block entries covering a series of adjacent
+ * 4k pages.
+ */
+void setup_pgtables(void)
+{
+ /* L1 entry points to L2 table */
+ pgt_map_l1_table(ttb_l1, (uintptr_t)_text_start, ttb_l2);
+
+ /* L2 entries: 2MB blocks */
+ /* .text & .rodata (Read-only, executable) */
+ flat_map_stage2(ttb_l2, (uintptr_t)_text_start, DESC_AF);
+
+ /* .data & .bss (Read-write, no-execute) */
+ flat_map_stage2(ttb_l2, (uintptr_t)_data_start, DESC_AF | DESC_PXN | DESC_UXN);
+
+ /* mte_page (Read-write, no-execute, AttrIndx=1) */
+ flat_map_stage2(ttb_l2, (uintptr_t)_tag_start, DESC_AF | DESC_PXN | DESC_UXN | DESC_ATTRINDX(1));
+
+ /* Set TTBR0_EL1 */
+ write_sysreg(ttb_l1, ttbr0_el1);
+
+ /* Set MAIR_EL1 */
+ write_sysreg(0xeeULL, mair_el1);
+
+ /* Set TCR_EL1 */
+ uint64_t tcr = TCR_EL1_IPS_40BIT | TCR_EL1_TG0_4KB | TCR_EL1_ORGN0_WBWA | TCR_EL1_IRGN0_WBWA | TCR_EL1_T0SZ(25);
+ write_sysreg(tcr, tcr_el1);
+ isb();
+
+ /* Enable MMU via SCTLR_EL1 */
+ uint64_t sctlr = read_sysreg(sctlr_el1);
+ sctlr &= ~(1ULL << 1); /* Clear A (alignment check) */
+ sctlr &= ~(1ULL << 19); /* Clear WXN */
+ sctlr |= SCTLR_EL1_M | SCTLR_EL1_C | SCTLR_EL1_I | SCTLR_EL1_SA;
+
+ dsb(sy);
+ write_sysreg(sctlr, sctlr_el1);
+ isb();
+}
diff --git a/tests/tcg/aarch64/Makefile.softmmu-target b/tests/tcg/aarch64/Makefile.softmmu-target
index c7f44803c73..5770ae1fb0c 100644
--- a/tests/tcg/aarch64/Makefile.softmmu-target
+++ b/tests/tcg/aarch64/Makefile.softmmu-target
@@ -6,10 +6,10 @@ AARCH64_SRC=$(SRC_PATH)/tests/tcg/aarch64
AARCH64_SYSTEM_SRC=$(AARCH64_SRC)/system
AARCH64_SYSTEM_LIB=$(AARCH64_SRC)/system/lib
-VPATH+=$(AARCH64_SYSTEM_SRC)
+VPATH+=$(AARCH64_SYSTEM_SRC) $(AARCH64_SYSTEM_LIB)
# These objects provide the basic boot code and helper functions for all tests
-CRT_OBJS=boot.o
+CRT_OBJS=boot.o pgtable.o
AARCH64_TEST_C_SRCS=$(wildcard $(AARCH64_SYSTEM_SRC)/*.c)
AARCH64_TEST_S_SRCS=$(AARCH64_SYSTEM_SRC)/mte.S
@@ -37,9 +37,12 @@ config-cc.mak: Makefile
# building head blobs
.PRECIOUS: $(CRT_OBJS)
-%.o: $(CRT_PATH)/%.S
+%.o: %.S
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -x assembler-with-cpp -Wa,--noexecstack -c $< -o $@
+%.o: %.c
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@
+
# Build and link the tests
%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
diff --git a/tests/tcg/aarch64/system/boot.S b/tests/tcg/aarch64/system/boot.S
index 8bfa4e4efc7..bee8d9372e7 100644
--- a/tests/tcg/aarch64/system/boot.S
+++ b/tests/tcg/aarch64/system/boot.S
@@ -243,102 +243,7 @@ at_testel:
msr vbar_el1, x0
/* Page table setup (identity mapping). */
- adrp x0, ttb
- add x0, x0, :lo12:ttb
- msr ttbr0_el1, x0
-
- /*
- * Setup a flat address mapping page-tables. Stage one simply
- * maps RAM to the first Gb. The stage2 tables have two 2mb
- * translation block entries covering a series of adjacent
- * 4k pages.
- */
-
- /* Stage 1 entry: indexed by IA[38:30] */
- adr x1, . /* phys address */
- bic x1, x1, #(1 << 30) - 1 /* 1GB alignment*/
- add x2, x0, x1, lsr #(30 - 3) /* offset in l1 page table */
-
- /* point to stage 2 table [47:12] */
- adrp x0, ttb_stage2
- orr x1, x0, #3 /* ptr to stage 2 */
- str x1, [x2]
-
- /* Stage 2 entries: indexed by IA[29:21] */
- ldr x5, =(((1 << 9) - 1) << 21)
-
- /* First block: .text/RO/execute enabled */
- adr x1, . /* phys address */
- bic x1, x1, #(1 << 21) - 1 /* 2mb block alignment */
- and x4, x1, x5 /* IA[29:21] */
- add x2, x0, x4, lsr #(21 - 3) /* offset in l2 page table */
- ldr x3, =0x401 /* attr(AF, block) */
- orr x1, x1, x3
- str x1, [x2] /* 1st 2mb (.text & rodata) */
-
- /* Second block: .data/RW/no execute */
- adrp x1, .data
- add x1, x1, :lo12:.data
- bic x1, x1, #(1 << 21) - 1 /* 2mb block alignment */
- and x4, x1, x5 /* IA[29:21] */
- add x2, x0, x4, lsr #(21 - 3) /* offset in l2 page table */
- ldr x3, =(3 << 53) | 0x401 /* attr(AF, NX, block) */
- orr x1, x1, x3
- str x1, [x2] /* 2nd 2mb (.data & .bss)*/
-
- /* Third block: at 'mte_page', set in kernel.ld */
- 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)
- /* attr(AF, NX, block, AttrIndx=Attr1) */
- ldr x3, =(3 << 53) | 0x401 | (1 << 2)
- orr x1, x1, x3
- str x1, [x2]
-
- /* Setup/enable the MMU. */
-
- /*
- * TCR_EL1 - Translation Control Registers
- *
- * 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
- * IRGN0[9:8] = Inner: Normal, WB Read-Alloc No Write-Alloc Cacheable
- * T0SZ[5:0] = 2^(64 - 25)
- *
- * The size of T0SZ controls what the initial lookup level. It
- * would be nice to start at level 2 but unfortunately for a
- * flat-mapping on the virt machine we need to handle IA's
- * 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)
- msr tcr_el1, x0
-
- mov x0, #0xee /* Inner/outer cacheable WB */
- msr mair_el1, x0
- isb
-
- /*
- * SCTLR_EL1 - System Control Register
- *
- * WXN[19] = 0 = no effect, Write does not imply XN (execute never)
- * I[12] = Instruction cachability control
- * SA[3] = SP alignment check
- * C[2] = Data cachability control
- * 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) */
- bic x0, x0, #(1 << 1) /* clear bit A(1) */
- bic x0, x0, #(1 << 19) /* clear WXN */
- orr x0, x0, x1 /* set bits */
-
- dsb sy
- msr sctlr_el1, x0
- isb
+ bl setup_pgtables
/*
* Enable FP/SVE registers. The standard C pre-amble will be
@@ -392,18 +297,6 @@ cmdline:
.space 128, 0
.align 12
-
- /* Translation table
- * @4k granuale: 9 bit lookup, 512 entries
- */
-ttb:
- .space 4096, 0
-
- .align 12
-ttb_stage2:
- .space 4096, 0
-
- .align 12
system_stack:
.space 4096, 0
system_stack_end:
diff --git a/tests/tcg/aarch64/system/kernel.ld b/tests/tcg/aarch64/system/kernel.ld
index aef043e31db..267ffcbe520 100644
--- a/tests/tcg/aarch64/system/kernel.ld
+++ b/tests/tcg/aarch64/system/kernel.ld
@@ -13,10 +13,12 @@ MEMORY {
SECTIONS {
.text : {
+ _text_start = .;
*(.text)
*(.rodata)
} >TXT
.data : {
+ _data_start = .;
*(.data)
*(.bss)
} >DAT
@@ -25,6 +27,7 @@ SECTIONS {
* Symbol 'mte_page' is used in boot.S to setup the PTE and in the mte.S
* test as the address that the MTE instructions operate on.
*/
+ _tag_start = .;
mte_page = .;
} >TAG
/DISCARD/ : {
--
2.47.3
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH 4/7] tests/tcg: move aarch64 page table setup to c code
2026-04-17 16:43 ` [PATCH 4/7] tests/tcg: move aarch64 page table setup to c code Alex Bennée
@ 2026-05-07 17:13 ` Jim MacArthur
0 siblings, 0 replies; 13+ messages in thread
From: Jim MacArthur @ 2026-05-07 17:13 UTC (permalink / raw)
To: qemu-devel; +Cc: Alex Bennee
On Fri, Apr 17, 2026 at 05:43:24PM +0100, Alex Bennée wrote:
> If we want more flexibility messing around with page tables lets do it
> without having to rely on assembly for it.
>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>
> ---
> AJB
> - a result of -O0 does mean each helper ends up with a stack frame
> being needed to do the relatively simple mask and shift. I've
> experimented with -O1 and trying to manually enable inlining but
> couldn't get anything to work.
> ---
> +#define DESC_AF (1ULL << 10)
> +#define DESC_ATTRINDX(i) ((uint64_t)(i) << 2)
> +#define DESC_NS (1ULL << 5)
> +#define DESC_UXN (1ULL << 53)
> +#define DESC_PXN (1ULL << 54)
I *think* you have UXN and PXN the wrong way round? See table D8-52; UXN is always 54.
It works fine in this case as we always use them together.
Otherwise,
Reviewed-by: Jim MacArthur <jim.macarthur@linaro.org>
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 5/7] tests/tcg: add HW page for aarch64 tests
2026-04-17 16:43 [PATCH 0/7] tests/tcg: more capabilities for aarch64-softmmu tests Alex Bennée
` (3 preceding siblings ...)
2026-04-17 16:43 ` [PATCH 4/7] tests/tcg: move aarch64 page table setup to c code Alex Bennée
@ 2026-04-17 16:43 ` Alex Bennée
2026-04-17 16:43 ` [PATCH 6/7] tests/tcg: create a mini-gic3 library Alex Bennée
2026-04-17 16:43 ` [PATCH 7/7] tests/tcg: add basic test for aarch64 wf[ie][t] insns Alex Bennée
6 siblings, 0 replies; 13+ messages in thread
From: Alex Bennée @ 2026-04-17 16:43 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-arm, Peter Maydell, Alex Bennée
If the test cases need to program items like the GIC we need to define
the region as Device-nGnRE memory. As this is for test cases just map
the whole first GB block (which is all HW in the -M virt machine).
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
tests/tcg/aarch64/system/lib/pgtable.c | 24 +++++++++++++++++-------
1 file changed, 17 insertions(+), 7 deletions(-)
diff --git a/tests/tcg/aarch64/system/lib/pgtable.c b/tests/tcg/aarch64/system/lib/pgtable.c
index a558f5f0dd5..5e7d95fd3d7 100644
--- a/tests/tcg/aarch64/system/lib/pgtable.c
+++ b/tests/tcg/aarch64/system/lib/pgtable.c
@@ -17,14 +17,18 @@ uint64_t ttb_l1[512] __attribute__((aligned(4096)));
uint64_t ttb_l2[512] __attribute__((aligned(4096)));
/*
- * Setup a flat address mapping page-tables. Stage one simply
- * maps RAM to the first Gb. The stage2 tables have two 2mb
- * translation block entries covering a series of adjacent
- * 4k pages.
+ * Setup a flat address mapping page-tables.
+ *
+ * ttb (Level 1):
+ * - Entry 0 [0 - 1GB]: 1GB Device block (for GIC and other H/W)
+ * - Entry 1 [1GB - 2GB]: Table entry pointing to ttb_l2 (for RAM)
*/
void setup_pgtables(void)
{
- /* L1 entry points to L2 table */
+ /* L1 entry 0: 1GB Device block mapping at 0x0 */
+ pgt_map_l1_block(ttb_l1, 0, 0, DESC_AF | DESC_ATTRINDX(2));
+
+ /* L1 entry 1: points to L2 table for finer permissions */
pgt_map_l1_table(ttb_l1, (uintptr_t)_text_start, ttb_l2);
/* L2 entries: 2MB blocks */
@@ -40,8 +44,14 @@ void setup_pgtables(void)
/* Set TTBR0_EL1 */
write_sysreg(ttb_l1, ttbr0_el1);
- /* Set MAIR_EL1 */
- write_sysreg(0xeeULL, mair_el1);
+ /*
+ * Set MAIR_EL1
+ *
+ * Attr0 (0xee): Normal memory, Outer/Inner WB/WA/Read-Alloc
+ * Attr1 (0x00): MTE page
+ * Attr2 (0x04): Device-nGnRE memory (for the first 1GB)
+ */
+ write_sysreg(0x0400eeULL, mair_el1);
/* Set TCR_EL1 */
uint64_t tcr = TCR_EL1_IPS_40BIT | TCR_EL1_TG0_4KB | TCR_EL1_ORGN0_WBWA | TCR_EL1_IRGN0_WBWA | TCR_EL1_T0SZ(25);
--
2.47.3
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 6/7] tests/tcg: create a mini-gic3 library
2026-04-17 16:43 [PATCH 0/7] tests/tcg: more capabilities for aarch64-softmmu tests Alex Bennée
` (4 preceding siblings ...)
2026-04-17 16:43 ` [PATCH 5/7] tests/tcg: add HW page for aarch64 tests Alex Bennée
@ 2026-04-17 16:43 ` Alex Bennée
2026-04-17 16:43 ` [PATCH 7/7] tests/tcg: add basic test for aarch64 wf[ie][t] insns Alex Bennée
6 siblings, 0 replies; 13+ messages in thread
From: Alex Bennée @ 2026-04-17 16:43 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-arm, Peter Maydell, Alex Bennée
Just enough GIC to trigger timer interrupts.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
tests/tcg/aarch64/system/lib/gicv3.h | 60 +++++++++++++++++++
tests/tcg/aarch64/system/lib/gicv3.c | 70 +++++++++++++++++++++++
tests/tcg/aarch64/Makefile.softmmu-target | 2 +
3 files changed, 132 insertions(+)
create mode 100644 tests/tcg/aarch64/system/lib/gicv3.h
create mode 100644 tests/tcg/aarch64/system/lib/gicv3.c
diff --git a/tests/tcg/aarch64/system/lib/gicv3.h b/tests/tcg/aarch64/system/lib/gicv3.h
new file mode 100644
index 00000000000..05c4c2f538b
--- /dev/null
+++ b/tests/tcg/aarch64/system/lib/gicv3.h
@@ -0,0 +1,60 @@
+/*
+ * GICv3 Helper Library
+ *
+ * Copyright (c) 2026 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef GICV3_H
+#define GICV3_H
+
+/*
+ * This duplicates just the bits of hw/intc/gicv3_internal.h we
+ * need for basic functionality.
+ */
+
+/* Virt machine GICv3 base addresses */
+#define GICD_BASE 0x08000000 /* c.f. VIRT_GIC_DIST */
+#define GICR_BASE 0x080a0000 /* c.f. VIRT_GIC_REDIST */
+
+/* Distributor registers */
+#define GICD_CTLR (GICD_BASE + 0x0000)
+#define GICD_TYPER (GICD_BASE + 0x0004)
+#define GICD_IIDR (GICD_BASE + 0x0008)
+
+/* Redistributor registers (per-CPU) */
+#define GICR_SGI_OFFSET 0x00010000
+
+#define GICR_CTLR 0x0000
+#define GICR_WAKER 0x0014
+
+#define GICR_IGROUPR0 (GICR_SGI_OFFSET + 0x0080)
+#define GICR_ISENABLER0 (GICR_SGI_OFFSET + 0x0100)
+#define GICR_IPRIORITYR (GICR_SGI_OFFSET + 0x0400)
+
+/* GICD_CTLR fields */
+#define GICD_CTLR_ENA_GRP0 (1U << 0)
+#define GICD_CTLR_ENA_GRP1NS (1U << 1)
+#define GICD_CTLR_ARE_NS (1U << 5)
+
+/* GICR_WAKER bits */
+#define GICR_WAKER_ProcessorSleep (1U << 1)
+#define GICR_WAKER_ChildrenAsleep (1U << 2)
+
+/**
+ * gicv3_init:
+ *
+ * Initialize GICv3 distributor and the redistributor for the current CPU.
+ */
+void gicv3_init(void);
+
+/**
+ * gicv3_enable_irq:
+ * @irq: The IRQ number to enable
+ *
+ * Enable the specified IRQ (SPI or PPI).
+ */
+void gicv3_enable_irq(unsigned int irq);
+
+#endif /* GICV3_H */
diff --git a/tests/tcg/aarch64/system/lib/gicv3.c b/tests/tcg/aarch64/system/lib/gicv3.c
new file mode 100644
index 00000000000..9cfd033a8ec
--- /dev/null
+++ b/tests/tcg/aarch64/system/lib/gicv3.c
@@ -0,0 +1,70 @@
+/*
+ * GICv3 Helper Library Implementation
+ *
+ * Copyright (c) 2026 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <stdint.h>
+#include "sysregs.h"
+#include "gicv3.h"
+
+static inline void write_reg(uintptr_t addr, uint32_t val)
+{
+ *(volatile uint32_t *) addr = val;
+}
+
+static inline uint32_t read_reg(uintptr_t addr)
+{
+ return *(volatile uint32_t *) addr;
+}
+
+void gicv3_init(void)
+{
+ uint32_t val;
+
+ /* 1. Enable Distributor ARE and Group 1 NS */
+ val = read_reg(GICD_CTLR);
+ val |= GICD_CTLR_ARE_NS | GICD_CTLR_ENA_GRP1NS;
+ write_reg(GICD_CTLR, val);
+
+ /* 2. Wake up Redistributor 0 and clear ProcessorSleep */
+ val = read_reg(GICR_BASE + GICR_WAKER);
+ val &= ~GICR_WAKER_ProcessorSleep;
+ write_reg(GICR_BASE + GICR_WAKER, val);
+
+ /* Wait for ChildrenAsleep to be cleared */
+ while (read_reg(GICR_BASE + GICR_WAKER) & GICR_WAKER_ChildrenAsleep) {
+ /* spin */
+ }
+
+ /* 3. Enable CPU interface */
+ /* Set Priority Mask to allow all interrupts */
+ write_sysreg(0xff, ICC_PMR_EL1);
+ /* Enable Group 1 Non-Secure interrupts */
+ write_sysreg(1, ICC_IGRPEN1_EL1);
+ isb();
+}
+
+void gicv3_enable_irq(unsigned int irq)
+{
+ if (irq < 32) {
+ /* PPI: use GICR_ISENABLER0 */
+ uintptr_t addr;
+
+ /* Set Group 1 */
+ addr = GICR_BASE + GICR_IGROUPR0;
+ write_reg(addr, read_reg(addr) | (1U << irq));
+
+ /* Set priority (0xa0) */
+ addr = GICR_BASE + GICR_IPRIORITYR + irq;
+ *(volatile uint8_t *)addr = 0xa0;
+
+ /* Enable it */
+ addr = GICR_BASE + GICR_ISENABLER0;
+ write_reg(addr, 1U << irq);
+ } else {
+ /* SPI: not implemented yet */
+ }
+}
diff --git a/tests/tcg/aarch64/Makefile.softmmu-target b/tests/tcg/aarch64/Makefile.softmmu-target
index 5770ae1fb0c..543d638e819 100644
--- a/tests/tcg/aarch64/Makefile.softmmu-target
+++ b/tests/tcg/aarch64/Makefile.softmmu-target
@@ -106,6 +106,8 @@ run-pauth-3:
$(call skip-test, "RUN of pauth-3", "not built")
endif
+gicv3.o: gicv3.c gicv3.h
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@
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
--
2.47.3
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 7/7] tests/tcg: add basic test for aarch64 wf[ie][t] insns
2026-04-17 16:43 [PATCH 0/7] tests/tcg: more capabilities for aarch64-softmmu tests Alex Bennée
` (5 preceding siblings ...)
2026-04-17 16:43 ` [PATCH 6/7] tests/tcg: create a mini-gic3 library Alex Bennée
@ 2026-04-17 16:43 ` Alex Bennée
2026-04-23 15:57 ` Jim MacArthur
6 siblings, 1 reply; 13+ messages in thread
From: Alex Bennée @ 2026-04-17 16:43 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-arm, Peter Maydell, Alex Bennée
This is based on a generated test case which I've since refined and
cleaned up.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
tests/tcg/aarch64/system/wfx.c | 143 ++++++++++++++++++++++
tests/tcg/aarch64/Makefile.softmmu-target | 8 ++
tests/tcg/aarch64/system/boot.S | 16 ++-
3 files changed, 164 insertions(+), 3 deletions(-)
create mode 100644 tests/tcg/aarch64/system/wfx.c
diff --git a/tests/tcg/aarch64/system/wfx.c b/tests/tcg/aarch64/system/wfx.c
new file mode 100644
index 00000000000..fa4c6761215
--- /dev/null
+++ b/tests/tcg/aarch64/system/wfx.c
@@ -0,0 +1,143 @@
+/*
+ * WFX Instructions Test (WFI, WFE, WFIT, WFET)
+ *
+ * Copyright (c) 2026 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <minilib.h>
+#include "sysregs.h"
+#include "gicv3.h"
+
+#define TIMEOUT 200000
+
+#define sev() asm volatile("sev" : : : "memory")
+#define sevl() asm volatile("sevl" : : : "memory")
+#define wfi() asm volatile("wfi" : : : "memory")
+#define wfe() asm volatile("wfe" : : : "memory")
+#define wfit(reg) asm volatile("wfit %0" : : "r" (reg) : "memory")
+#define wfet(reg) asm volatile("wfet %0" : : "r" (reg) : "memory")
+
+#define enable_irq() asm volatile("msr daifclr, #2" : : : "memory")
+#define disable_irq() asm volatile("msr daifset, #2" : : : "memory")
+
+static bool check_elapsed(uint64_t start, uint64_t threshold, const char *test, bool more)
+{
+ uint64_t end = read_sysreg(cntvct_el0);
+ uint64_t elapsed = end - start;
+ if (more ? elapsed < threshold : elapsed > threshold) {
+ ml_printf("FAILED: %s %s (%ld ticks)\n", test,
+ more ? "woke too early" : "slept despite SEV",
+ elapsed);
+ return false;
+ }
+ ml_printf("PASSED (%ld ticks)\n", elapsed);
+ return true;
+}
+
+int main(void)
+{
+ uint64_t start, timeout;
+
+ gicv3_init();
+ gicv3_enable_irq(27); /* Virtual Timer PPI */
+
+ ml_printf("WFx[T] Tests\n");
+
+ /*
+ * 1. Test WFI with timer interrupt
+ *
+ * We don't have a full interrupt handler, but WFI should wake up
+ * when the interrupt is pending even if we have it masked at the CPU.
+ * PSTATE.I is set by boot code.
+ *
+ * We unmask interrupts here to ensure the CPU can take the minimal
+ * exception handler defined in boot.S.
+ */
+ ml_printf("Testing WFI...");
+
+ start = read_sysreg(cntvct_el0);
+ write_sysreg(TIMEOUT, cntv_tval_el0);
+ write_sysreg(1, cntv_ctl_el0); /* Enable timer, no mask */
+ isb();
+
+ enable_irq();
+ wfi();
+ disable_irq();
+
+ if (!check_elapsed(start, TIMEOUT, "WFI", true)) {
+ return 1;
+ }
+
+ /* Validate the timer fired and then disable for future tests */
+ if (!read_sysreg(cntv_ctl_el0) & 0x4) {
+ ml_printf("Time ISTATUS not set!\n");
+ return 1;
+ }
+ write_sysreg(0, cntv_ctl_el0);
+
+ /*
+ * 2. Test WFE and SEV[L]
+ *
+ * There are two SEV instructions, the normal one is a broadcast
+ * from any PE on the system, the other is local only.
+ * Functionally they have the same effect (setting the event
+ * register) and should be immediately consumed by the WFE.
+ *
+ * As we want to detect an early exit the sense of the timeout
+ * check is reversed.
+ */
+ ml_printf("Testing WFE/SEV...");
+ sev();
+ start = read_sysreg(cntvct_el0);
+ wfe();
+ if (!check_elapsed(start, TIMEOUT, "WFE", false)) {
+ return 1;
+ }
+
+ ml_printf("Testing WFE/SEVL...");
+ sevl();
+ start = read_sysreg(cntvct_el0);
+ wfe();
+ if (!check_elapsed(start, TIMEOUT, "WFE", false)) {
+ return 1;
+ }
+
+ /*
+ * 3. Test WFIT
+ *
+ * With the timer now disabled and no other IRQ sources firing the
+ * WFIT instruction should timeout. Although the architecture
+ * permits this being treated as a NOP we have enabled it.
+ */
+ ml_printf("Testing WFIT...");
+ start = read_sysreg(cntvct_el0);
+ timeout = start + TIMEOUT;
+ wfit(timeout);
+ if (!check_elapsed(start, TIMEOUT, "WFIT", true)) {
+ return 1;
+ }
+
+ /*
+ * 4. Test WFET
+ *
+ * Much like WFIT there are no IRQs to wake us up. However the
+ * event_register is a latch so we must first consume the event
+ * register with a normal WFE before we do the timeout version.
+ */
+ ml_printf("Testing WFET...");
+ sev();
+ wfe();
+ start = read_sysreg(cntvct_el0);
+ timeout = start + TIMEOUT;
+ wfet(timeout);
+ if (!check_elapsed(start, TIMEOUT, "WFET", true)) {
+ return 1;
+ }
+
+ ml_printf("ALL WFX TESTS PASSED\n");
+ return 0;
+}
diff --git a/tests/tcg/aarch64/Makefile.softmmu-target b/tests/tcg/aarch64/Makefile.softmmu-target
index 543d638e819..6a1e867fba0 100644
--- a/tests/tcg/aarch64/Makefile.softmmu-target
+++ b/tests/tcg/aarch64/Makefile.softmmu-target
@@ -108,6 +108,14 @@ endif
gicv3.o: gicv3.c gicv3.h
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@
+
+wfx: CFLAGS += -march=armv8.7-a
+wfx: LDFLAGS += gicv3.o
+wfx: gicv3.o
+
+QEMU_GICV3_MACHINE=-M virt,gic-version=3 -cpu max -display none
+run-wfx: QEMU_OPTS=$(QEMU_GICV3_MACHINE) $(QEMU_BASE_ARGS) -kernel
+
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
diff --git a/tests/tcg/aarch64/system/boot.S b/tests/tcg/aarch64/system/boot.S
index bee8d9372e7..ba9000a749d 100644
--- a/tests/tcg/aarch64/system/boot.S
+++ b/tests/tcg/aarch64/system/boot.S
@@ -35,7 +35,7 @@ vector_table:
/* Current EL with SPx. */
ventry curr_spx_sync /* Synchronous */
- ventry curr_spx_irq /* IRQ/vIRQ */
+ ventry curr_spx_irq /* Basic handler for IRQ/vIRQ */
ventry curr_spx_fiq /* FIQ/vFIQ */
ventry curr_spx_serror /* SError/VSError */
@@ -54,13 +54,12 @@ vector_table:
.text
.align 4
- /* Common vector handling for now */
+ /* Apart from curr_spx_irq we error out with an unexpected exception */
curr_sp0_sync:
curr_sp0_irq:
curr_sp0_fiq:
curr_sp0_serror:
curr_spx_sync:
-curr_spx_irq:
curr_spx_fiq:
curr_spx_serror:
lower_a64_sync:
@@ -275,6 +274,17 @@ _exit:
semihosting_call
/* never returns */
+ /*
+ * IRQ handler
+ */
+ .global curr_spx_irq
+curr_spx_irq:
+ /* Minimal IRQ handler: just mask the timer and return */
+ mrs x0, cntv_ctl_el0
+ orr x0, x0, #2 /* IMASK=1 */
+ msr cntv_ctl_el0, x0
+ eret
+
/*
* Helper Functions
*/
--
2.47.3
^ permalink raw reply related [flat|nested] 13+ messages in thread