diff mbox

[kvm-unit-tests,1/2] arm/arm64: Add self-modifying code test

Message ID 1441185926-61587-2-git-send-email-a.spyridakis@virtualopensystems.com
State New
Headers show

Commit Message

Alexander Spyridakis Sept. 2, 2015, 9:25 a.m. UTC
Basic torture test that continuously modifies a single instruction
opcode and checks if all modifications were done and run as expected.

Signed-off-by: Alexander Spyridakis <a.spyridakis@virtualopensystems.com>
---
 arm/self-modifying-test.c    | 109 +++++++++++++++++++++++++++++++++++++++++++
 config/config-arm-common.mak |   2 +
 2 files changed, 111 insertions(+)
 create mode 100644 arm/self-modifying-test.c
diff mbox

Patch

diff --git a/arm/self-modifying-test.c b/arm/self-modifying-test.c
new file mode 100644
index 0000000..cab47a0
--- /dev/null
+++ b/arm/self-modifying-test.c
@@ -0,0 +1,109 @@ 
+/*
+ * Basic self-modifying code test case
+ *
+ * Copyright (C) 2015 Virtual Open Systems SAS
+ * Author: Alexander Spyridakis <a.spyridakis@virtualopensystems.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+
+#include <asm/smp.h>
+#include <asm/mmu.h>
+#include <asm/spinlock.h>
+
+#define LOOP_SIZE 100000
+
+int result;
+static cpumask_t smp_test_complete;
+static struct spinlock lock;
+
+void self_modifying_test(void)
+{
+	extern void *smc;
+	static int toggle;
+	int i, cpu = smp_processor_id(), *ptr = (int *)&smc;
+
+	printf("CPU%d starting test\n", cpu);
+
+	for (i = 0; i < LOOP_SIZE; i++) {
+		/* Don't run concurrently with other CPUs*/
+		spin_lock(&lock);
+
+		/* A simple snippet that increments a memory value which
+		   will be modified immediately after. Before running,
+		   invalidate the instruction and data cache for that
+		   specific virtual address */
+#ifdef __arm__
+		asm("mcr	p15, 0, %0, c7, c6, 1\n" /* DCIMVAC */
+			"mcr	p15, 0, %0, c7, c5, 1\n" /* ICIMVAU */
+#else
+		asm("dc	ivac, %0\n"
+			"ic	ivau, %0\n"
+#endif
+			"dsb	ish\n"
+			"isb\n"
+			"smc:\n"
+			"add	%1, %1, #1\n"
+			"str	%1, [%2]\n"
+			:: "r" (ptr), "r" (result), "r" (&result));
+
+		/* Overwrite the previous labelled opcode,
+		   toggle between incrementing by one or two */
+		toggle ^= 1;
+		if (toggle)
+#ifdef __arm__
+			*ptr += 1;
+		else
+			*ptr -= 1;
+#else
+		{
+			*ptr &= ~(1 << 10);
+			*ptr |=  (1 << 11);
+		} else {
+			*ptr |=  (1 << 10);
+			*ptr &= ~(1 << 11);
+		}
+#endif
+
+		spin_unlock(&lock);
+	}
+
+	cpumask_set_cpu(cpu, &smp_test_complete);
+	if (cpu != 0)
+		halt();
+}
+
+int main(int argc, char **argv)
+{
+	int cpu, calc;
+	(void)argc, (void)argv;
+
+	/* Set memory as writeable, on ARMv7 we need to re-enable the MMU */
+#ifdef __arm__
+	mmu_disable();
+	flush_tlb_all();
+	mmu_set_range_ptes(mmu_idmap, PHYS_OFFSET, PHYS_OFFSET, PHYS_END,
+			__pgprot(PTE_WBWA));
+	mmu_enable(mmu_idmap);
+#else
+	mmu_set_range_ptes(mmu_idmap, PHYS_OFFSET, PHYS_OFFSET, PHYS_END,
+			__pgprot(PTE_WBWA));
+	flush_tlb_all();
+#endif
+
+	for_each_present_cpu(cpu) {
+		if (cpu == 0)
+			continue;
+		smp_boot_secondary(cpu, self_modifying_test);
+	}
+
+	self_modifying_test();
+
+	while (!cpumask_full(&smp_test_complete))
+		cpu_relax();
+
+	calc = LOOP_SIZE * nr_cpus + (LOOP_SIZE * nr_cpus / 2);
+	report("Result: %d - Expected: %d\n", result == calc, result, calc);
+
+	return report_summary();
+}
diff --git a/config/config-arm-common.mak b/config/config-arm-common.mak
index 698555d..74a73e4 100644
--- a/config/config-arm-common.mak
+++ b/config/config-arm-common.mak
@@ -10,6 +10,7 @@  ifeq ($(LOADADDR),)
 endif
 
 tests-common = \
+	$(TEST_DIR)/self-modifying-test.flat \
 	$(TEST_DIR)/selftest.flat \
 	$(TEST_DIR)/spinlock-test.flat
 
@@ -70,3 +71,4 @@  test_cases: $(generated_files) $(tests-common) $(tests)
 
 $(TEST_DIR)/selftest.elf: $(cstart.o) $(TEST_DIR)/selftest.o
 $(TEST_DIR)/spinlock-test.elf: $(cstart.o) $(TEST_DIR)/spinlock-test.o
+$(TEST_DIR)/self-modifying-test.elf: $(cstart.o) $(TEST_DIR)/self-modifying-test.o