aboutsummaryrefslogtreecommitdiffstats
path: root/tests/tcg/multiarch/system
diff options
context:
space:
mode:
authorTimos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>2023-10-10 11:40:56 +0000
committerTimos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>2023-10-10 11:40:56 +0000
commite02cda008591317b1625707ff8e115a4841aa889 (patch)
treeaee302e3cf8b59ec2d32ec481be3d1afddfc8968 /tests/tcg/multiarch/system
parentcc668e6b7e0ffd8c9d130513d12053cf5eda1d3b (diff)
Introduce Virtio-loopback epsilon release:
Epsilon release introduces a new compatibility layer which make virtio-loopback design to work with QEMU and rust-vmm vhost-user backend without require any changes. Signed-off-by: Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com> Change-Id: I52e57563e08a7d0bdc002f8e928ee61ba0c53dd9
Diffstat (limited to 'tests/tcg/multiarch/system')
-rw-r--r--tests/tcg/multiarch/system/Makefile.softmmu-target35
-rw-r--r--tests/tcg/multiarch/system/hello.c14
-rw-r--r--tests/tcg/multiarch/system/memory.c476
3 files changed, 525 insertions, 0 deletions
diff --git a/tests/tcg/multiarch/system/Makefile.softmmu-target b/tests/tcg/multiarch/system/Makefile.softmmu-target
new file mode 100644
index 000000000..625ed792c
--- /dev/null
+++ b/tests/tcg/multiarch/system/Makefile.softmmu-target
@@ -0,0 +1,35 @@
+# -*- Mode: makefile -*-
+#
+# Multiarch system tests
+#
+# We just collect the tests together here and rely on the actual guest
+# architecture to add to the test dependancies and deal with the
+# complications of building.
+#
+
+MULTIARCH_SRC=$(SRC_PATH)/tests/tcg/multiarch
+MULTIARCH_SYSTEM_SRC=$(MULTIARCH_SRC)/system
+VPATH+=$(MULTIARCH_SYSTEM_SRC)
+
+MULTIARCH_TEST_SRCS=$(wildcard $(MULTIARCH_SYSTEM_SRC)/*.c)
+MULTIARCH_TESTS = $(patsubst $(MULTIARCH_SYSTEM_SRC)/%.c, %, $(MULTIARCH_TEST_SRCS))
+
+ifneq ($(HAVE_GDB_BIN),)
+GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py
+
+run-gdbstub-memory: memory
+ $(call run-test, $@, $(GDB_SCRIPT) \
+ --gdb $(HAVE_GDB_BIN) \
+ --qemu $(QEMU) \
+ --output $<.gdb.out \
+ --qargs \
+ "-monitor none -display none -chardev file$(COMMA)path=$<.out$(COMMA)id=output $(QEMU_OPTS)" \
+ --bin $< --test $(MULTIARCH_SRC)/gdbstub/memory.py, \
+ "softmmu gdbstub support")
+
+else
+run-gdbstub-%:
+ $(call skip-test, "gdbstub test $*", "need working gdb")
+endif
+
+MULTIARCH_RUNS += run-gdbstub-memory
diff --git a/tests/tcg/multiarch/system/hello.c b/tests/tcg/multiarch/system/hello.c
new file mode 100644
index 000000000..821dc0ef0
--- /dev/null
+++ b/tests/tcg/multiarch/system/hello.c
@@ -0,0 +1,14 @@
+/*
+ * Hello World, system test version
+ *
+ * We don't have the benefit of libc, just builtin C primitives and
+ * whatever is in minilib.
+ */
+
+#include <minilib.h>
+
+int main(void)
+{
+ ml_printf("Hello World\n");
+ return 0;
+}
diff --git a/tests/tcg/multiarch/system/memory.c b/tests/tcg/multiarch/system/memory.c
new file mode 100644
index 000000000..41c7f66e2
--- /dev/null
+++ b/tests/tcg/multiarch/system/memory.c
@@ -0,0 +1,476 @@
+/*
+ * Memory Test
+ *
+ * This is intended to test the softmmu code and ensure we properly
+ * behave across normal and unaligned accesses across several pages.
+ * We are not replicating memory tests for stuck bits and other
+ * hardware level failures but looking for issues with different size
+ * accesses when access is:
+ *
+ * - unaligned at various sizes (if -DCHECK_UNALIGNED set)
+ * - spanning a (softmmu) page
+ * - sign extension when loading
+ */
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <minilib.h>
+
+#ifndef CHECK_UNALIGNED
+# error "Target does not specify CHECK_UNALIGNED"
+#endif
+
+#define MEM_PAGE_SIZE 4096 /* nominal 4k "pages" */
+#define TEST_SIZE (MEM_PAGE_SIZE * 4) /* 4 pages */
+
+#define ARRAY_SIZE(x) ((sizeof(x) / sizeof((x)[0])))
+
+__attribute__((aligned(MEM_PAGE_SIZE)))
+static uint8_t test_data[TEST_SIZE];
+
+typedef void (*init_ufn) (int offset);
+typedef bool (*read_ufn) (int offset);
+typedef bool (*read_sfn) (int offset, bool nf);
+
+static void pdot(int count)
+{
+ if (count % 128 == 0) {
+ ml_printf(".");
+ }
+}
+
+/*
+ * Helper macros for shift/extract so we can keep our endian handling
+ * in one place.
+ */
+#define BYTE_SHIFT(b, pos) ((uint64_t)b << (pos * 8))
+#define BYTE_EXTRACT(b, pos) ((b >> (pos * 8)) & 0xff)
+
+/*
+ * Fill the data with ascending value bytes.
+ *
+ * Currently we only support Little Endian machines so write in
+ * ascending address order. When we read higher address bytes should
+ * either be zero or higher than the lower bytes.
+ */
+
+static void init_test_data_u8(int unused_offset)
+{
+ uint8_t count = 0, *ptr = &test_data[0];
+ int i;
+ (void)(unused_offset);
+
+ ml_printf("Filling test area with u8:");
+ for (i = 0; i < TEST_SIZE; i++) {
+ *ptr++ = count++;
+ pdot(i);
+ }
+ ml_printf("done\n");
+}
+
+/*
+ * Full the data with alternating positive and negative bytes. This
+ * should mean for reads larger than a byte all subsequent reads will
+ * stay either negative or positive. We never write 0.
+ */
+
+static inline uint8_t get_byte(int index, bool neg)
+{
+ return neg ? (0xff << (index % 7)) : (0xff >> ((index % 6) + 1));
+}
+
+static void init_test_data_s8(bool neg_first)
+{
+ uint8_t top, bottom, *ptr = &test_data[0];
+ int i;
+
+ ml_printf("Filling test area with s8 pairs (%s):",
+ neg_first ? "neg first" : "pos first");
+ for (i = 0; i < TEST_SIZE / 2; i++) {
+ *ptr++ = get_byte(i, neg_first);
+ *ptr++ = get_byte(i, !neg_first);
+ pdot(i);
+ }
+ ml_printf("done\n");
+}
+
+/*
+ * Zero the first few bytes of the test data in preparation for
+ * new offset values.
+ */
+static void reset_start_data(int offset)
+{
+ uint32_t *ptr = (uint32_t *) &test_data[0];
+ int i;
+ for (i = 0; i < offset; i++) {
+ *ptr++ = 0;
+ }
+}
+
+static void init_test_data_u16(int offset)
+{
+ uint8_t count = 0;
+ uint16_t word, *ptr = (uint16_t *) &test_data[offset];
+ const int max = (TEST_SIZE - offset) / sizeof(word);
+ int i;
+
+ ml_printf("Filling test area with u16 (offset %d, %p):", offset, ptr);
+
+ reset_start_data(offset);
+
+ for (i = 0; i < max; i++) {
+ uint8_t low = count++, high = count++;
+ word = BYTE_SHIFT(high, 1) | BYTE_SHIFT(low, 0);
+ *ptr++ = word;
+ pdot(i);
+ }
+ ml_printf("done @ %p\n", ptr);
+}
+
+static void init_test_data_u32(int offset)
+{
+ uint8_t count = 0;
+ uint32_t word, *ptr = (uint32_t *) &test_data[offset];
+ const int max = (TEST_SIZE - offset) / sizeof(word);
+ int i;
+
+ ml_printf("Filling test area with u32 (offset %d, %p):", offset, ptr);
+
+ reset_start_data(offset);
+
+ for (i = 0; i < max; i++) {
+ uint8_t b4 = count++, b3 = count++;
+ uint8_t b2 = count++, b1 = count++;
+ word = BYTE_SHIFT(b1, 3) | BYTE_SHIFT(b2, 2) | BYTE_SHIFT(b3, 1) | b4;
+ *ptr++ = word;
+ pdot(i);
+ }
+ ml_printf("done @ %p\n", ptr);
+}
+
+static void init_test_data_u64(int offset)
+{
+ uint8_t count = 0;
+ uint64_t word, *ptr = (uint64_t *) &test_data[offset];
+ const int max = (TEST_SIZE - offset) / sizeof(word);
+ int i;
+
+ ml_printf("Filling test area with u64 (offset %d, %p):", offset, ptr);
+
+ reset_start_data(offset);
+
+ for (i = 0; i < max; i++) {
+ uint8_t b8 = count++, b7 = count++;
+ uint8_t b6 = count++, b5 = count++;
+ uint8_t b4 = count++, b3 = count++;
+ uint8_t b2 = count++, b1 = count++;
+ word = BYTE_SHIFT(b1, 7) | BYTE_SHIFT(b2, 6) | BYTE_SHIFT(b3, 5) |
+ BYTE_SHIFT(b4, 4) | BYTE_SHIFT(b5, 3) | BYTE_SHIFT(b6, 2) |
+ BYTE_SHIFT(b7, 1) | b8;
+ *ptr++ = word;
+ pdot(i);
+ }
+ ml_printf("done @ %p\n", ptr);
+}
+
+static bool read_test_data_u16(int offset)
+{
+ uint16_t word, *ptr = (uint16_t *)&test_data[offset];
+ int i;
+ const int max = (TEST_SIZE - offset) / sizeof(word);
+
+ ml_printf("Reading u16 from %#lx (offset %d):", ptr, offset);
+
+ for (i = 0; i < max; i++) {
+ uint8_t high, low;
+ word = *ptr++;
+ high = (word >> 8) & 0xff;
+ low = word & 0xff;
+ if (high < low && high != 0) {
+ ml_printf("Error %d < %d\n", high, low);
+ return false;
+ } else {
+ pdot(i);
+ }
+
+ }
+ ml_printf("done @ %p\n", ptr);
+ return true;
+}
+
+static bool read_test_data_u32(int offset)
+{
+ uint32_t word, *ptr = (uint32_t *)&test_data[offset];
+ int i;
+ const int max = (TEST_SIZE - offset) / sizeof(word);
+
+ ml_printf("Reading u32 from %#lx (offset %d):", ptr, offset);
+
+ for (i = 0; i < max; i++) {
+ uint8_t b1, b2, b3, b4;
+ int zeros = 0;
+ word = *ptr++;
+
+ b1 = word >> 24 & 0xff;
+ b2 = word >> 16 & 0xff;
+ b3 = word >> 8 & 0xff;
+ b4 = word & 0xff;
+
+ zeros += (b1 == 0 ? 1 : 0);
+ zeros += (b2 == 0 ? 1 : 0);
+ zeros += (b3 == 0 ? 1 : 0);
+ zeros += (b4 == 0 ? 1 : 0);
+ if (zeros > 1) {
+ ml_printf("Error @ %p, more zeros than expected: %d, %d, %d, %d",
+ ptr - 1, b1, b2, b3, b4);
+ return false;
+ }
+
+ if ((b1 < b2 && b1 != 0) ||
+ (b2 < b3 && b2 != 0) ||
+ (b3 < b4 && b3 != 0)) {
+ ml_printf("Error %d, %d, %d, %d", b1, b2, b3, b4);
+ return false;
+ } else {
+ pdot(i);
+ }
+ }
+ ml_printf("done @ %p\n", ptr);
+ return true;
+}
+
+static bool read_test_data_u64(int offset)
+{
+ uint64_t word, *ptr = (uint64_t *)&test_data[offset];
+ int i;
+ const int max = (TEST_SIZE - offset) / sizeof(word);
+
+ ml_printf("Reading u64 from %#lx (offset %d):", ptr, offset);
+
+ for (i = 0; i < max; i++) {
+ uint8_t b1, b2, b3, b4, b5, b6, b7, b8;
+ int zeros = 0;
+ word = *ptr++;
+
+ b1 = ((uint64_t) (word >> 56)) & 0xff;
+ b2 = ((uint64_t) (word >> 48)) & 0xff;
+ b3 = ((uint64_t) (word >> 40)) & 0xff;
+ b4 = (word >> 32) & 0xff;
+ b5 = (word >> 24) & 0xff;
+ b6 = (word >> 16) & 0xff;
+ b7 = (word >> 8) & 0xff;
+ b8 = (word >> 0) & 0xff;
+
+ zeros += (b1 == 0 ? 1 : 0);
+ zeros += (b2 == 0 ? 1 : 0);
+ zeros += (b3 == 0 ? 1 : 0);
+ zeros += (b4 == 0 ? 1 : 0);
+ zeros += (b5 == 0 ? 1 : 0);
+ zeros += (b6 == 0 ? 1 : 0);
+ zeros += (b7 == 0 ? 1 : 0);
+ zeros += (b8 == 0 ? 1 : 0);
+ if (zeros > 1) {
+ ml_printf("Error @ %p, more zeros than expected: %d, %d, %d, %d, %d, %d, %d, %d",
+ ptr - 1, b1, b2, b3, b4, b5, b6, b7, b8);
+ return false;
+ }
+
+ if ((b1 < b2 && b1 != 0) ||
+ (b2 < b3 && b2 != 0) ||
+ (b3 < b4 && b3 != 0) ||
+ (b4 < b5 && b4 != 0) ||
+ (b5 < b6 && b5 != 0) ||
+ (b6 < b7 && b6 != 0) ||
+ (b7 < b8 && b7 != 0)) {
+ ml_printf("Error %d, %d, %d, %d, %d, %d, %d, %d",
+ b1, b2, b3, b4, b5, b6, b7, b8);
+ return false;
+ } else {
+ pdot(i);
+ }
+ }
+ ml_printf("done @ %p\n", ptr);
+ return true;
+}
+
+/* Read the test data and verify at various offsets */
+read_ufn read_ufns[] = { read_test_data_u16,
+ read_test_data_u32,
+ read_test_data_u64 };
+
+bool do_unsigned_reads(int start_off)
+{
+ int i;
+ bool ok = true;
+
+ for (i = 0; i < ARRAY_SIZE(read_ufns) && ok; i++) {
+#if CHECK_UNALIGNED
+ int off;
+ for (off = start_off; off < 8 && ok; off++) {
+ ok = read_ufns[i](off);
+ }
+#else
+ ok = read_ufns[i](start_off);
+#endif
+ }
+
+ return ok;
+}
+
+static bool do_unsigned_test(init_ufn fn)
+{
+#if CHECK_UNALIGNED
+ bool ok = true;
+ int i;
+ for (i = 0; i < 8 && ok; i++) {
+ fn(i);
+ ok = do_unsigned_reads(i);
+ }
+ return ok;
+#else
+ fn(0);
+ return do_unsigned_reads(0);
+#endif
+}
+
+/*
+ * We need to ensure signed data is read into a larger data type to
+ * ensure that sign extension is working properly.
+ */
+
+static bool read_test_data_s8(int offset, bool neg_first)
+{
+ int8_t *ptr = (int8_t *)&test_data[offset];
+ int i;
+ const int max = (TEST_SIZE - offset) / 2;
+
+ ml_printf("Reading s8 pairs from %#lx (offset %d):", ptr, offset);
+
+ for (i = 0; i < max; i++) {
+ int16_t first, second;
+ bool ok;
+ first = *ptr++;
+ second = *ptr++;
+
+ if (neg_first && first < 0 && second > 0) {
+ pdot(i);
+ } else if (!neg_first && first > 0 && second < 0) {
+ pdot(i);
+ } else {
+ ml_printf("Error %d %c %d\n", first, neg_first ? '<' : '>', second);
+ return false;
+ }
+ }
+ ml_printf("done @ %p\n", ptr);
+ return true;
+}
+
+static bool read_test_data_s16(int offset, bool neg_first)
+{
+ int16_t *ptr = (int16_t *)&test_data[offset];
+ int i;
+ const int max = (TEST_SIZE - offset) / (sizeof(*ptr));
+
+ ml_printf("Reading s16 from %#lx (offset %d, %s):", ptr,
+ offset, neg_first ? "neg" : "pos");
+
+ for (i = 0; i < max; i++) {
+ int32_t data = *ptr++;
+
+ if (neg_first && data < 0) {
+ pdot(i);
+ } else if (data > 0) {
+ pdot(i);
+ } else {
+ ml_printf("Error %d %c 0\n", data, neg_first ? '<' : '>');
+ return false;
+ }
+ }
+ ml_printf("done @ %p\n", ptr);
+ return true;
+}
+
+static bool read_test_data_s32(int offset, bool neg_first)
+{
+ int32_t *ptr = (int32_t *)&test_data[offset];
+ int i;
+ const int max = (TEST_SIZE - offset) / (sizeof(int32_t));
+
+ ml_printf("Reading s32 from %#lx (offset %d, %s):",
+ ptr, offset, neg_first ? "neg" : "pos");
+
+ for (i = 0; i < max; i++) {
+ int64_t data = *ptr++;
+
+ if (neg_first && data < 0) {
+ pdot(i);
+ } else if (data > 0) {
+ pdot(i);
+ } else {
+ ml_printf("Error %d %c 0\n", data, neg_first ? '<' : '>');
+ return false;
+ }
+ }
+ ml_printf("done @ %p\n", ptr);
+ return true;
+}
+
+/*
+ * Read the test data and verify at various offsets
+ *
+ * For everything except bytes all our reads should be either positive
+ * or negative depending on what offset we are reading from. Currently
+ * we only handle LE systems.
+ */
+read_sfn read_sfns[] = { read_test_data_s8,
+ read_test_data_s16,
+ read_test_data_s32 };
+
+bool do_signed_reads(bool neg_first)
+{
+ int i;
+ bool ok = true;
+
+ for (i = 0; i < ARRAY_SIZE(read_sfns) && ok; i++) {
+#if CHECK_UNALIGNED
+ int off;
+ for (off = 0; off < 8 && ok; off++) {
+ bool nf = i == 0 ? neg_first ^ (off & 1) : !(neg_first ^ (off & 1));
+ ok = read_sfns[i](off, nf);
+ }
+#else
+ ok = read_sfns[i](0, i == 0 ? neg_first : !neg_first);
+#endif
+ }
+
+ return ok;
+}
+
+init_ufn init_ufns[] = { init_test_data_u8,
+ init_test_data_u16,
+ init_test_data_u32,
+ init_test_data_u64 };
+
+int main(void)
+{
+ int i;
+ bool ok = true;
+
+ /* Run through the unsigned tests first */
+ for (i = 0; i < ARRAY_SIZE(init_ufns) && ok; i++) {
+ ok = do_unsigned_test(init_ufns[i]);
+ }
+
+ if (ok) {
+ init_test_data_s8(false);
+ ok = do_signed_reads(false);
+ }
+
+ if (ok) {
+ init_test_data_s8(true);
+ ok = do_signed_reads(true);
+ }
+
+ ml_printf("Test complete: %s\n", ok ? "PASSED" : "FAILED");
+ return ok ? 0 : -1;
+}