Add the boot code and semihosting helpers needed to run the multiarch
system tests on riscv64, and add riscv64 to MULTIARCH_SOFTMMU_TARGETS.
The aarch64 makefile was used as a guide for the make rules.

boot.S does not clear bss as the libmem plugin test would count the
stores and fail with a mismatch. Instead the BSS is described as
PT_LOAD, so the QEMU ELF loader fills the region with zero, the same as
aarch64 and loongarch64.

Signed-off-by: Joel Stanley <[email protected]>
---
 tests/tcg/riscv64/system.c                | 30 +++++++++++++++++
 tests/tcg/Makefile.target                 |  2 +-
 tests/tcg/riscv64/Makefile.softmmu-target | 40 ++++++++++++-----------
 tests/tcg/riscv64/boot.S                  | 23 +++++++++++++
 4 files changed, 75 insertions(+), 20 deletions(-)
 create mode 100644 tests/tcg/riscv64/system.c
 create mode 100644 tests/tcg/riscv64/boot.S

diff --git a/tests/tcg/riscv64/system.c b/tests/tcg/riscv64/system.c
new file mode 100644
index 000000000000..08196a540f96
--- /dev/null
+++ b/tests/tcg/riscv64/system.c
@@ -0,0 +1,30 @@
+/*
+ * RISC-V semihosting support for multiarch test suite
+ *
+ * Copyright 2026 Tenstorrent USA Inc
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "semicall.h"
+
+#define SYS_WRITEC      0x3
+#define SYS_EXIT        0x18
+
+#define ADP_Stopped_ApplicationExit 0x20026
+
+void __sys_outc(char c)
+{
+    __semi_call(SYS_WRITEC, (uintptr_t)&c);
+}
+
+void _exit(int code)
+{
+    const uintptr_t args[2] = { ADP_Stopped_ApplicationExit, (uintptr_t)code };
+
+    __semi_call(SYS_EXIT, (uintptr_t)args);
+
+    /* Hang if QEMU fails to exit */
+    while (1) {
+        asm volatile("wfi");
+    }
+}
diff --git a/tests/tcg/Makefile.target b/tests/tcg/Makefile.target
index 1b83824ff4e7..d4dd0fec650d 100644
--- a/tests/tcg/Makefile.target
+++ b/tests/tcg/Makefile.target
@@ -129,7 +129,7 @@ else
 EXTRA_CFLAGS += -ffreestanding -fno-stack-protector
 
 # We skip the multiarch tests if the target hasn't provided a boot.S
-MULTIARCH_SOFTMMU_TARGETS = i386 alpha aarch64 arm loongarch64 s390x x86_64
+MULTIARCH_SOFTMMU_TARGETS = i386 alpha aarch64 arm loongarch64 s390x x86_64 
riscv64
 
 ifneq ($(filter $(TARGET_NAME),$(MULTIARCH_SOFTMMU_TARGETS)),)
 -include $(SRC_PATH)/tests/tcg/minilib/Makefile.target
diff --git a/tests/tcg/riscv64/Makefile.softmmu-target 
b/tests/tcg/riscv64/Makefile.softmmu-target
index f2850a194084..82e8fe2664b0 100644
--- a/tests/tcg/riscv64/Makefile.softmmu-target
+++ b/tests/tcg/riscv64/Makefile.softmmu-target
@@ -5,9 +5,11 @@
 TEST_SRC = $(SRC_PATH)/tests/tcg/riscv64
 VPATH += $(TEST_SRC)
 
+CRT_OBJS = boot.o system.o
+
 LINK_SCRIPT = $(TEST_SRC)/semihost.ld
-LDFLAGS = -T $(LINK_SCRIPT)
-CFLAGS += -g -Og
+LDFLAGS = -Wl,-T$(LINK_SCRIPT) -static -nostdlib $(MINILIB_OBJS) -lgcc
+CFLAGS += -g -Og $(MINILIB_INC)
 
 # Used by riscv64 tcg tests and shared 'multiarch' tests
 QEMU_CPU = rv64
@@ -53,23 +55,23 @@ test-zicclsm-off.o: test-zicclsm.S
        $(call quiet-command, \
          $(CC) $(CFLAGS) $< -Wa$(COMMA)--noexecstack -c -o $@, CC, $@)
 
-EXTRA_RUNS += run-plugin-doubletrap
-run-plugin-doubletrap: doubletrap
-       $(call run-test, $<, \
-         $(QEMU) -monitor none -display none \
-                 -chardev file$(COMMA)path=$<.out$(COMMA)id=output \
-                 -plugin ../plugins/libdiscons.so -d plugin -D $<.pout \
-                 $(QEMU_OPTS) $<)
-
-EXTRA_RUNS += run-plugin-interruptedmemory
-run-plugin-interruptedmemory: interruptedmemory
-       $(call run-test, $<, \
-         $(QEMU) -monitor none -display none \
-                 -chardev file$(COMMA)path=$<.out$(COMMA)id=output \
-                 -plugin ../plugins/libdiscons.so -d plugin -D $<.pout \
-                 $(QEMU_OPTS) $<)
+ifeq ($(CONFIG_PLUGIN),y)
+EXTRA_RUNS_WITH_PLUGIN += run-plugin-doubletrap-with-libdiscons.so \
+       run-plugin-interruptedmemory-with-libdiscons.so
+endif
 
 CLEANFILES += interruptedmemory doubletrap
 
-# We don't currently support the multiarch system tests
-undefine MULTIARCH_TESTS
+# Multiarch tests
+TESTS += $(MULTIARCH_TESTS)
+EXTRA_RUNS += $(MULTIARCH_RUNS)
+
+.PRECIOUS: $(CRT_OBJS)
+
+# Build and link the multiarch tests
+%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
+       $(call quiet-command, \
+        $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) $(CRT_OBJS), CC, 
$@)
+
+# Default is zicclsm=true, so misaligned accesses must work
+memory: private CFLAGS += -DCHECK_UNALIGNED=1
diff --git a/tests/tcg/riscv64/boot.S b/tests/tcg/riscv64/boot.S
new file mode 100644
index 000000000000..b403549345a1
--- /dev/null
+++ b/tests/tcg/riscv64/boot.S
@@ -0,0 +1,23 @@
+/*
+ * RISC-V boot code for multiarch test suite
+ *
+ * Copyright 2026 Tenstorrent USA Inc
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#define MSTATUS_VS          0x00000600
+#define MSTATUS_FS          0x00006000
+
+.section .text._start
+        .global _start
+        .type _start, @function
+_start:
+        /* Enable FPU and vector unit */
+        li      t0, (MSTATUS_FS | MSTATUS_VS)
+        csrs    mstatus, t0
+        la      sp, __stack_top
+        call    main
+
+exit:
+        /* exit with main()'s return code */
+        call    _exit
-- 
2.47.3


Reply via email to